Search code examples
c#asp.netkenticokentico-12

Kentico how to read a POST Value in a custom form control


I'm working on a Kentico app V12 (after the same code will be deployed to other installations from 12 to 7) and I added a new form control. In my case the control is for the Google Recaptcha V3 token (so I don't need to save the value), so these are my steps:

  • I added the new form control through the Kentico interface
  • I added a new field in one form to test the functionality
  • I added the Javascript part to manage the recaptcha validation

Actually I'm able to manage all the flow on the client side, my goal now it's validate the token before saving the data, so I added this code on my ascx file

public partial class CMSModules_ReCAPTCHA : FormEngineUserControl
{

    private static string GOOGLE_RECAPTCHA_LIBRARY_URL = "https://www.google.com/recaptcha/api.js";

    public override bool IsValid()
    {
        return this.Validate();
    }

    public override object Value
    {
        get
        {
            // How can I get the value?
        }
        set { }
    }

    private bool Validate()
    {
        // Here's the code to validate the token
    }
}

If I send the form I can see on the inspector that the token is sent, but how can I get that value on my ascx file and get an error message if the validation is not successful? I tried with CMS.Helpers.ValidationHelper.GetString(Form.GetFieldValue("reCAPTCHA")) but it's not working. reCAPTCHA it's the field's name, the value is sent as g-recaptcha-response.


Solution

  • So the way we have handled this is to add in a HiddenField control on the front end file (.ascx) that HiddenField gets populated by the javascript that you are running to work with the standard recaptcha stuff (as you mention). Then on postback of the form, that HiddenField has the token value that your Value property can use.

    On the .ascx of the formcontrol

    <asp:HiddenField runat="server" ID="recaptchaToken" ClientIDMode="Static" />
    

    Then on your .ascx.cs file of the formcontrol

    public override object Value
    {
        get
        {
            return recaptchaToken.Value;
        }
        set
        {
            recaptchaToken.Value = (string)value;
        }
    }
    

    That way it should be there on the Postback of the form that you have the form control on.

    Remember your JavaScript needs to populate the value as well. Like:

    document.getElementById('recaptchaToken').value = token; //the one from Google
    

    You may also have to handle the validation. For that we override the IsValid member and call out to Google for Validation with the token. Down and dirty version would look like:

    public override bool IsValid()
    {
        if (Value == null || String.IsNullOrEmpty(Value.ToString()))
            return false;
    
        var tokenResponse = Value.ToString();
    
        // Clear for next time around
        Value = "";
    
        return ReCaptchaCheckPassed(GoogleSecretKey, tokenResponse);
    }
    
    public static bool ReCaptchaCheckPassed(string GoogleSecretKey, string RecaptchaResponse)
    {
        HttpClient httpClient = new HttpClient();
    
        var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret={googleSecretKey}&response={RecaptchaResponse}").Result;
    
        if (res.StatusCode != HttpStatusCode.OK)
            return false;
    
        string JSONres = res.Content.ReadAsStringAsync().Result;
    
        dynamic JSONdata = JObject.Parse(JSONres);
    
        if (JSONdata.success != "true")
            return false;
    
        return true;
    }