diff --git a/samples/KITT.Web.ReCaptcha.Samples.Http/Program.cs b/samples/KITT.Web.ReCaptcha.Samples.Http/Program.cs
index e210a1d..52467f6 100644
--- a/samples/KITT.Web.ReCaptcha.Samples.Http/Program.cs
+++ b/samples/KITT.Web.ReCaptcha.Samples.Http/Program.cs
@@ -11,7 +11,7 @@
builder.Services.AddCors(
options => options.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()));
-builder.Services.AddReCaptchaV2(options =>
+builder.Services.AddReCaptchaV2HttpClient(options =>
{
options.SecretKey = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"; // this is the v2 test secret
});
diff --git a/samples/v2/KITT.Web.ReCaptcha.Sample.v2.BlazorServer/Program.cs b/samples/v2/KITT.Web.ReCaptcha.Sample.v2.BlazorServer/Program.cs
index 5d8896f..af340c0 100644
--- a/samples/v2/KITT.Web.ReCaptcha.Sample.v2.BlazorServer/Program.cs
+++ b/samples/v2/KITT.Web.ReCaptcha.Sample.v2.BlazorServer/Program.cs
@@ -6,7 +6,7 @@
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
-builder.Services.AddReCaptchaV2(options =>
+builder.Services.AddReCaptchaV2HttpClient(options =>
{
options.SecretKey = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe";
});
diff --git a/samples/v2/KITT.Web.ReCaptcha.Sample.v2.Wasm.Api/Program.cs b/samples/v2/KITT.Web.ReCaptcha.Sample.v2.Wasm.Api/Program.cs
index 699dc33..80b6017 100644
--- a/samples/v2/KITT.Web.ReCaptcha.Sample.v2.Wasm.Api/Program.cs
+++ b/samples/v2/KITT.Web.ReCaptcha.Sample.v2.Wasm.Api/Program.cs
@@ -5,7 +5,7 @@
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices((ctx, services) =>
{
- services.AddReCaptchaV2(options => options.SecretKey = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe");
+ services.AddReCaptchaV2HttpClient(options => options.SecretKey = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe");
})
.Build();
diff --git a/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/KITT.Web.ReCaptcha.Sample.v3.BlazorServer.csproj b/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/KITT.Web.ReCaptcha.Sample.v3.BlazorServer.csproj
index 0dd2276..7f4c9b6 100644
--- a/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/KITT.Web.ReCaptcha.Sample.v3.BlazorServer.csproj
+++ b/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/KITT.Web.ReCaptcha.Sample.v3.BlazorServer.csproj
@@ -8,6 +8,7 @@
+
diff --git a/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/Pages/Index.razor b/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/Pages/Index.razor
index e095d69..73a8d33 100644
--- a/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/Pages/Index.razor
+++ b/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/Pages/Index.razor
@@ -2,7 +2,8 @@
@using System.ComponentModel.DataAnnotations
@using KITT.Web.ReCaptcha.Blazor.v3
-@inject ReCaptchaService ReCaptcha
+@inject Blazor.v3.ReCaptchaService ReCaptchaClient
+@inject Http.v3.ReCaptchaService ReCaptchaHttp
KITT ReCaptcha v3 - Blazor Server sample
@@ -45,11 +46,24 @@
{
try
{
- var reCaptchaClientResponse = await ReCaptcha.VerifyAsync(action: "submit");
+ var reCaptchaClientResponse = await ReCaptchaClient.VerifyAsync(action: "submit");
if (reCaptchaClientResponse.Succeeded)
{
- message = "reCaptcha validated on client successfully!";
- isSuccessMessage = true;
+ var serverSideResponse = await ReCaptchaHttp.VerifyAsync(
+ reCaptchaClientResponse.Response,
+ action: "submit");
+
+ if (serverSideResponse.Success)
+ {
+ message = "reCaptcha validated successfully!";
+ isSuccessMessage = true;
+ }
+ else
+ {
+ message = string.Join(",", serverSideResponse.ErrorCodes);
+ isSuccessMessage = false;
+ }
+
}
else
{
diff --git a/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/Program.cs b/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/Program.cs
index 547d6c5..3c1c56c 100644
--- a/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/Program.cs
+++ b/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/Program.cs
@@ -1,4 +1,5 @@
using KITT.Web.ReCaptcha.Blazor.v3;
+using KITT.Web.ReCaptcha.Http.v3;
var builder = WebApplication.CreateBuilder(args);
@@ -6,7 +7,9 @@
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
-builder.Services.AddReCaptchaV3(options => options.SiteKey = builder.Configuration["ReCaptcha:SiteKey"]!);
+builder.Services
+ .AddReCaptchaV3(options => options.SiteKey = builder.Configuration["ReCaptcha:SiteKey"]!)
+ .AddReCaptchaV3HttpClient(options => options.SecretKey = builder.Configuration["ReCaptcha:SecretKey"]!);
var app = builder.Build();
diff --git a/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/appsettings.Development.json b/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/appsettings.Development.json
index 770d3e9..1c6a417 100644
--- a/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/appsettings.Development.json
+++ b/samples/v3/KITT.Web.ReCaptcha.Sample.v3.BlazorServer/appsettings.Development.json
@@ -5,5 +5,9 @@
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
+ },
+ "ReCaptcha": {
+ "SiteKey": "6Le_GAgpAAAAACUDETr8C09Fb-rr1ZU0eP9_5kX_",
+ "SecretKey": "6Le_GAgpAAAAADWRoVeXqSg7BZL_cBWwPpt_sBdp"
}
}
diff --git a/src/KITT.Web.ReCaptcha.Http/KITT.Web.ReCaptcha.Http.csproj b/src/KITT.Web.ReCaptcha.Http/KITT.Web.ReCaptcha.Http.csproj
index bd13c20..95e2c59 100644
--- a/src/KITT.Web.ReCaptcha.Http/KITT.Web.ReCaptcha.Http.csproj
+++ b/src/KITT.Web.ReCaptcha.Http/KITT.Web.ReCaptcha.Http.csproj
@@ -6,7 +6,7 @@
enable
True
KITT.Web.ReCaptcha.Http
- 0.1.0
+ 0.2.0
Alberto Mori
Contains the service which calls Google reCaptcha verification endpoint for server-side validation
https://github.com/albx/KITT.Web.ReCaptcha
diff --git a/src/KITT.Web.ReCaptcha.Http/README.md b/src/KITT.Web.ReCaptcha.Http/README.md
index 709c4cc..0c5116d 100644
--- a/src/KITT.Web.ReCaptcha.Http/README.md
+++ b/src/KITT.Web.ReCaptcha.Http/README.md
@@ -13,14 +13,15 @@ It can be installed using the ```dotnet add package``` command or the NuGet wiza
dotnet add package KITT.Web.ReCaptcha.Http
```
-## Usage
+## reCaptcha v2
+### Usage
The project gives you an HttpClient service which expose a *VerifyAsync* method to verify the reCaptcha response send by the user from the client.
-Add the namespace ```KITT.Web.ReCaptcha.Http.v2``` to your ```Program.cs``` and use the *AddReCaptchaV2* extension method to your ```IServiceCollection``` instance:
+Add the namespace ```KITT.Web.ReCaptcha.Http.v2``` to your ```Program.cs``` and use the *AddReCaptchaV2HttpClient* extension method to your ```IServiceCollection``` instance:
```
-builder.Services.AddReCaptchaV2(options =>
+builder.Services.AddReCaptchaV2HttpClient(options =>
{
options.SecretKey = "";
});
@@ -42,7 +43,7 @@ app.MapPost("/send", async (ReCaptchaService reCaptchaService, [FromBody] SendRe
});
```
-## Methods
+### Methods
The ```VerifyAsync``` method has the following input parameters:
@@ -59,4 +60,57 @@ The method returns an instance of the ```ReCaptchaResponse``` class, which have
|**Success**|*bool*: whether the verification ended successfully|
|**ChallengeTimestamp**|*DateTime*: the timestamp of the challenge load|
|**Hostname**|*string*: the hostname of the site where the reCAPTCHA was solved|
-|**ErrorCodes**|*IEnumerable<string>*: the optional list of error codes (see [Google's official documentation](https://developers.google.com/recaptcha/docs/verify#error_code_reference))|
\ No newline at end of file
+|**ErrorCodes**|*IEnumerable<string>*: the optional list of error codes (see [Google's official documentation](https://developers.google.com/recaptcha/docs/verify#error_code_reference))|
+
+## reCaptcha v3
+### Usage
+
+The project gives you an HttpClient service which expose a *VerifyAsync* method to verify the reCaptcha response send by the user from the client.
+
+Add the namespace ```KITT.Web.ReCaptcha.Http.v3``` to your ```Program.cs``` and use the *AddReCaptchaV3HttpClient* extension method to your ```IServiceCollection``` instance:
+
+```
+builder.Services.AddReCaptchaV3HttpClient(options =>
+{
+ options.SecretKey = "";
+});
+```
+
+Then you can inject the ```ReCaptchaService``` class whenever you need and call the ```VerifyAsync``` like this:
+
+```
+app.MapPost("/send", async (ReCaptchaService reCaptchaService, [FromBody] SendRequest request) =>
+{
+ // Here you call the reCaptcha server-side validation
+ var captchaResponse = await reCaptchaService.VerifyAsync(request.CaptchaResponse, request.Action);
+ if (!captchaResponse.Success)
+ {
+ return Results.BadRequest(captchaResponse.ErrorCodes);
+ }
+
+ return Results.Ok();
+});
+```
+
+### Methods
+
+The ```VerifyAsync``` method has the following input parameters:
+
+|Property|Description|
+|---|---|
+|**response** (Required)|*string*: The user response token provided by the reCAPTCHA client-side integration on your site.|
+|**action** (Required)|*string*: The action value used to configure the reCaptcha|
+|**remoteIp** (Optional)|*string*: The user's IP address. (Default: *null*)|
+|**cancellationToken** (Optional)|*CancellationToken*: a cancellation token instance (Default: *CancellationToken.None*)|
+
+The method returns an instance of the ```ReCaptchaResponse``` class, which have the following properties:
+
+|Property|Description|
+|---|---|
+|**Success**|*bool*: whether the verification ended successfully|
+|**Score**|*double*: the score for the request (from 0.0 to 1.0)|
+|**Action**|*string*: the action name for this request|
+|**ChallengeTimestamp**|*DateTime*: the timestamp of the challenge load|
+|**Hostname**|*string*: the hostname of the site where the reCAPTCHA was solved|
+|**ErrorCodes**|*IEnumerable<string>*: the optional list of error codes (see [Google's official documentation](https://developers.google.com/recaptcha/docs/verify#error_code_reference))|
+
diff --git a/src/KITT.Web.ReCaptcha.Http/v2/ServiceCollectionExtensions.cs b/src/KITT.Web.ReCaptcha.Http/v2/ServiceCollectionExtensions.cs
index 010719d..79edc01 100644
--- a/src/KITT.Web.ReCaptcha.Http/v2/ServiceCollectionExtensions.cs
+++ b/src/KITT.Web.ReCaptcha.Http/v2/ServiceCollectionExtensions.cs
@@ -14,7 +14,7 @@ public static class ServiceCollectionExtensions
/// The instance
/// The action used to configure the options
/// The instance for method chaining
- public static IServiceCollection AddReCaptchaV2(
+ public static IServiceCollection AddReCaptchaV2HttpClient(
this IServiceCollection services,
Action configureOptions)
{
diff --git a/src/KITT.Web.ReCaptcha.Http/v3/ReCaptchaResponse.cs b/src/KITT.Web.ReCaptcha.Http/v3/ReCaptchaResponse.cs
index aa1a3b0..c490c5b 100644
--- a/src/KITT.Web.ReCaptcha.Http/v3/ReCaptchaResponse.cs
+++ b/src/KITT.Web.ReCaptcha.Http/v3/ReCaptchaResponse.cs
@@ -2,6 +2,9 @@
namespace KITT.Web.ReCaptcha.Http.v3;
+///
+/// Defines the response of the call to the reCaptcha verification endpoint
+///
public record ReCaptchaResponse
{
///
@@ -10,9 +13,15 @@ public record ReCaptchaResponse
[JsonPropertyName("success")]
public bool Success { get; init; }
+ ///
+ /// Gets the score for the request
+ ///
[JsonPropertyName("score")]
public double Score { get; init; }
+ ///
+ /// Gets the action name for the request
+ ///
[JsonPropertyName("action")]
public string Action { get; init; } = string.Empty;
diff --git a/src/KITT.Web.ReCaptcha.Http/v3/ReCaptchaService.cs b/src/KITT.Web.ReCaptcha.Http/v3/ReCaptchaService.cs
index ce40503..9b126c3 100644
--- a/src/KITT.Web.ReCaptcha.Http/v3/ReCaptchaService.cs
+++ b/src/KITT.Web.ReCaptcha.Http/v3/ReCaptchaService.cs
@@ -4,20 +4,39 @@
namespace KITT.Web.ReCaptcha.Http.v3;
+///
+/// This service verifies the captcha response from the client calling the Google API
+///
public class ReCaptchaService
{
private readonly HttpClient _httpClient;
private readonly ReCaptchaConfiguration _configuration;
+ ///
+ /// Constructs the service instance
+ ///
+ /// The instance configured to call the Google API
+ /// The instance which contains the server side secret key
+ /// Thrown when or instance is null
public ReCaptchaService(HttpClient httpClient, IOptions reCaptchaConfigurationOptions)
{
- _httpClient = httpClient;
+ _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_configuration = reCaptchaConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(reCaptchaConfigurationOptions));
ThrowIfConfigurationIsNotValid(_configuration);
}
+ ///
+ /// Verifies the response of the reCaptcha client side integration
+ ///
+ /// (Required) The user response token provided by the reCAPTCHA client-side integration on your site.
+ /// (Required) The action value used to configure the reCaptcha
+ /// (Optional) The user's IP address.
+ /// A instance
+ /// The received from the call to the Google verification endpoint
+ /// Thrown when response is null or white-space
+ /// Thrown when the action returned from the server call does not match with the specified value from the client
public async Task VerifyAsync(string response, string action, string? remoteIp = null, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(response))
diff --git a/src/KITT.Web.ReCaptcha.Http/v3/ServiceCollectionExtensions.cs b/src/KITT.Web.ReCaptcha.Http/v3/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000..a239743
--- /dev/null
+++ b/src/KITT.Web.ReCaptcha.Http/v3/ServiceCollectionExtensions.cs
@@ -0,0 +1,30 @@
+using KITT.Web.ReCaptcha.Http.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace KITT.Web.ReCaptcha.Http.v3;
+
+///
+/// Defines the extensions methods to register in the IoC container
+///
+public static class ServiceCollectionExtensions
+{
+ ///
+ /// Adds service and configures all the options needed
+ ///
+ /// The instance
+ /// The action used to configure the options
+ /// The instance for method chaining
+ public static IServiceCollection AddReCaptchaV3HttpClient(
+ this IServiceCollection services,
+ Action configureOptions)
+ {
+ services.Configure(configureOptions);
+
+ services.AddHttpClient();
+
+ services.AddHttpClient(
+ client => client.BaseAddress = new Uri("https://www.google.com/recaptcha/"));
+
+ return services;
+ }
+}
diff --git a/tests/KITT.Web.ReCaptcha.Http.Test/v3/ReCaptchaServiceTest.cs b/tests/KITT.Web.ReCaptcha.Http.Test/v3/ReCaptchaServiceTest.cs
index c7771db..0b156aa 100644
--- a/tests/KITT.Web.ReCaptcha.Http.Test/v3/ReCaptchaServiceTest.cs
+++ b/tests/KITT.Web.ReCaptcha.Http.Test/v3/ReCaptchaServiceTest.cs
@@ -8,7 +8,7 @@ namespace KITT.Web.ReCaptcha.Http.Test.v3;
public class ReCaptchaServiceTest
{
- private static readonly Uri _googleRecaptchaBaseUri = new Uri("https://www.google.com/recaptcha/");
+ private static readonly Uri _googleRecaptchaBaseUri = new("https://www.google.com/recaptcha/");
#region Ctor tests
[Theory]
@@ -17,7 +17,7 @@ public class ReCaptchaServiceTest
[InlineData(" ")]
public void Ctor_Should_Throw_Argument_Exception_If_Secret_Key_Is_Missing(string secretKey)
{
- using HttpClient httpClient = new HttpClient();
+ using HttpClient httpClient = new();
IOptions reCaptchaConfigurationOptions = Options.Create(new ReCaptchaConfiguration { SecretKey = secretKey });
var ex = Assert.Throws(() => new ReCaptchaService(httpClient, reCaptchaConfigurationOptions));