TimothyMeadows / reCAPTCHA.AspNetCore

Google reCAPTCHA v2/v3 for .NET Core 3.x
MIT License
145 stars 49 forks source link

Unable to prevent form submission when HTML 5 required fields are empty using RecaptchaV2Invisible #67

Closed vt-cloud closed 4 years ago

vt-cloud commented 4 years ago

When using standard HTML 5 "required" field validation, failure to enter text into a form input box would normally prevent the form from submitting. This works as expected when using RecaptchaV2Checkbox and RecaptchaV3HiddenInput, however with RecaptchaV2Invisible the form is submitted regardless of the validation state.

I would expect that the form is only submitted and the Recaptcha triggered if the form passes HTML 5 validation.

Being able to validate client-side before any requests are made is highly desireable from a user perspective and can make coding a lot simpler. Can you make the RecaptchaV2Invisible respect the form validation state and only trigger if valid please?

TimothyMeadows commented 4 years ago

I can agree with that sentiment that it should try and validate for html form validation. However, i can't commit to adding such a feature at this time. When time permits, or should a contributor decide to take this on i will try and help as i can. I will flag this an open enhancement for now.

Due to all the various "validation" methods beyond just basic html (which might be the hardest to capture) it might be best to just add a validation callback and allow the developers that register the method to "block" submitting unless they return true. This will allow each developer to hook that method to the validation framework of there choice.

Further ideas can be considered.

vt-cloud commented 4 years ago

My first instinct was to attempt to block the form submission using a standard JQuery binding to the submit event. However this was unsuccessful and I was unable to prevent submission whenever the submit (or any) button was implemented with the id set to "recaptcha".

I'm not completely sure if the issue is with reCAPTCHA.AspNetCore or with Google's implementation. I can't see a way to stop the reCaptcha being submitted when it is bound to the button performing the submission and I'm not familiar enough with the Google implementation to comment.

I can see perhaps two methods to solve this issue:

  1. If it is possible to bind RecaptchaV2Invisible to an element other than the submit button I think that this would solve the issue. I attempted this using a hidden button that was quickly swapped in and submitted however this prevented the tiles being displayed and caused some other issues that I didn't have time to explore.

  2. If it is not possible to stop the submission of the reCaptcha, at least the form can be prevented from submitting if the submit() event of the form was triggered. This is currently not happening because programmatic calls to submit() don't trigger a DOM event. Perhaps adding a dispatchEvent to the programmatic form submission would provide a solution?

I understand that this could be difficult to implement and if I find a valid solution I will let you know.

nmg196 commented 4 years ago

Hi,

I solved this by using the JS callback to populate a required hidden (dummy) field which I had added to the model with the [Required] attribute.

Something seems a bit wrong with the syntax of the Html Helper though as the documented way doesn't work (it claims settings is null) and you have to pass the settings in TWICE. What am I doing wrong @TimothyMeadows ?

<form method="post">
    <div asp-validation-summary="All" class="text-danger"></div>

    <div class="form-group">
        <label asp-for="Input.Email"></label>
        <input asp-for="Input.Email" class="form-control" />
        <input asp-for="Input.Captcha" type="hidden" />
        <span asp-validation-for="Input.Email" class="text-danger"></span>
    </div>

    @(Html.Recaptcha<RecaptchaV2Checkbox>(RecaptchaSettings?.Value, 
           new RecaptchaV2Checkbox { Settings = RecaptchaSettings?.Value, SuccessCallback =  "RecaptchaCallback" }))

    <script>
        $.validator.setDefaults({ 
            ignore: [] // allow validation of hidden fields
        });

        function RecaptchaCallback() {
            $("#Input_Captcha").val("captcha activated");
        }
    </script>
    <br />

    <button type="submit" class="btn btn-primary">Submit</button>
</form>
TimothyMeadows commented 4 years ago

Hi this was a bug and will be fixed in the next version. See this commit https://github.com/TimothyMeadows/reCAPTCHA.AspNetCore/commit/609b9dd364c3d9f560c6cc9ce8bda4aff288b3b4

Further i also included a contact example of how to bypass the submit issue using 2 buttons (one hidden) this might be more useful for others using js based validation. See this example https://github.com/TimothyMeadows/reCAPTCHA.AspNetCore/blob/master/reCAPTCHA.AspNetCore.Example/Views/Home/Contact3.cshtml

TimothyMeadows commented 4 years ago

This has been resolved in https://github.com/TimothyMeadows/reCAPTCHA.AspNetCore/releases/tag/3.0.6

nmg196 commented 4 years ago

Thanks for the quick fix :)