Reputation: 83
I searched a lot of sources for the captcha integration, but didn't see how to integrate it into Blazor Webassembly. Please help me to have some resources available. Thanks very much.
(Most of my problem is that the .razor component cannot use the tag)
Upvotes: 2
Views: 7071
Reputation: 31
The important thing is to call grecaptcha.render
after the the Blazor component has rendered, i.e. call it from OnAfterRenderAsync
.
Captcha.razor
@inject IJSRuntime JS
<span id="recaptcha" data-sitekey="@SiteKey"></span>
@code {
[Parameter]
public string SiteKey { get; set; }
public async Task<string> GetResponse()
{
return await JS.InvokeAsync<string>("grecaptcha.getResponse");
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.InvokeVoidAsync("grecaptcha.render", "recaptcha");
}
}
}
Using the above:
...
<Captcha @ref="captchaComponent" SiteKey="@SiteKey"></Captcha>
...
@code
{
Captcha captchaComponent;
...
var reCaptchaResponse = await captchaComponent.GetResponse();
...
}
index.html
<script src="https://www.google.com/recaptcha/api.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
A complete project that uses this is on GitHub here https://github.com/semata-com/SemataWebApp
Upvotes: 3
Reputation: 27803
I searched a lot of sources for the captcha integration, but didn't see how to integrate it into Blazor Webassembly.
To achieve the requirement of integrating the reCAPTCHA widget into Blazor Webassembly, you can try:
Create and include these two js files within wwwroot/Scripts
folder
scriptLoader.js
// loadScript: returns a promise that completes when the script loads
window.loadScript = function (scriptPath) {
// check list - if already loaded we can ignore
if (loaded[scriptPath]) {
console.log(scriptPath + " already loaded");
// return 'empty' promise
return new this.Promise(function (resolve, reject) {
resolve();
});
}
return new Promise(function (resolve, reject) {
// create JS library script element
var script = document.createElement("script");
if (scriptPath === "https://www.google.com/recaptcha/api.js") {
script.src = scriptPath + "?render=explicit";
script.async = true;
script.defer = true;
}
script.src = scriptPath;
script.type = "text/javascript";
console.log(scriptPath + " created");
// flag as loading/loaded
loaded[scriptPath] = true;
// if the script returns okay, return resolve
script.onload = function () {
console.log(scriptPath + " loaded ok");
resolve(scriptPath);
};
// if it fails, return reject
script.onerror = function () {
console.log(scriptPath + " load failed");
reject(scriptPath);
}
// scripts will load at end of body
document["body"].appendChild(script);
});
}
// store list of what scripts we've loaded
loaded = [];
Note: the code referenced from this github example could help dynamically load JavaScript library, and I did some modification.
JsOfReCAPTCHA.js
function render_recaptcha(dotNetObj, selector, sitekey) {
return grecaptcha.render(selector, {
'sitekey': sitekey,
'callback': (response) => { dotNetObj.invokeMethodAsync('CallbackOnSuccess', response); },
'expired-callback': () => { dotNetObj.invokeMethodAsync('CallbackOnExpired'); }
});
};
function getResponse(widgetId) {
return grecaptcha.getResponse(widgetId);
}
Create and add a script reference in index.html
<script src="Scripts/scriptLoader.js"></script>
Create ReCAPTCHA.razor with following code
@page "/recaptcha"
@using System.ComponentModel
@inject IJSRuntime JS;
<h3>reCAPTCHA</h3>
<div id="recaptcha_container"></div>
<button type="button" class="btn btn-primary" @onclick="ShowResponse">Show Response</button>
<br />
@reCAPTCHA_response
@code {
private int WidgetId;
public string reCAPTCHA_response;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await JS.InvokeVoidAsync("loadScript", "https://www.google.com/recaptcha/api.js");
await JS.InvokeVoidAsync("loadScript", "Scripts/JsOfReCAPTCHA.js");
if (firstRender)
{
WidgetId = await JS.InvokeAsync<int>("render_recaptcha", DotNetObjectReference.Create(this), "recaptcha_container", "your_site_key_here");
}
await base.OnAfterRenderAsync(firstRender);
}
[JSInvokable, EditorBrowsable(EditorBrowsableState.Never)]
public void CallbackOnSuccess(string response)
{
reCAPTCHA_response = response;
}
[JSInvokable, EditorBrowsable(EditorBrowsableState.Never)]
public void CallbackOnExpired()
{
//...
}
private void ShowResponse()
{
reCAPTCHA_response = $"The response for the reCAPTCHA widget: {reCAPTCHA_response}";
}
}
Test Result
Upvotes: 5