Browse Source

CMS Kit: Cache generated reCaptcha result

pull/17565/head
Engincan VESKE 3 years ago
parent
commit
dc2e58442d
  1. 4
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs
  2. 14
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs
  3. 3
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml
  4. 5
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaOptions.cs
  5. 47
      modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs

4
modules/cms-kit/src/Volo.CmsKit.Public.Web/Controllers/CmsKitPublicCommentsController.cs

@ -37,7 +37,7 @@ public class CmsKitPublicCommentsController : CmsKitPublicControllerBase
{ {
CheckCaptchaTokenNullity(input.CaptchaToken); CheckCaptchaTokenNullity(input.CaptchaToken);
SimpleMathsCaptchaGenerator.Validate(input.CaptchaToken.Value, input.CaptchaAnswer); await SimpleMathsCaptchaGenerator.ValidateAsync(input.CaptchaToken.Value, input.CaptchaAnswer);
} }
var dto = ObjectMapper.Map<CreateCommentWithParametersInput, CreateCommentInput> (input); var dto = ObjectMapper.Map<CreateCommentWithParametersInput, CreateCommentInput> (input);
@ -51,7 +51,7 @@ public class CmsKitPublicCommentsController : CmsKitPublicControllerBase
{ {
CheckCaptchaTokenNullity(input.CaptchaToken); CheckCaptchaTokenNullity(input.CaptchaToken);
SimpleMathsCaptchaGenerator.Validate(input.CaptchaToken.Value, input.CaptchaAnswer); await SimpleMathsCaptchaGenerator.ValidateAsync(input.CaptchaToken.Value, input.CaptchaAnswer);
} }
await CommentPublicAppService.UpdateAsync(id, input); await CommentPublicAppService.UpdateAsync(id, input);

14
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/CommentingViewComponent.cs

@ -76,26 +76,30 @@ public class CommentingViewComponent : AbpViewComponent
LoginUrl = loginUrl, LoginUrl = loginUrl,
Comments = comments.OrderByDescending(i => i.CreationTime).ToList() Comments = comments.OrderByDescending(i => i.CreationTime).ToList()
}; };
await ConvertMarkdownTextsToHtml(viewModel); await ConvertMarkdownTextsToHtml(viewModel);
if (CmsKitCommentOptions.IsRecaptchaEnabled) if (CmsKitCommentOptions.IsRecaptchaEnabled)
{ {
CaptchaOutput = GetCaptcha(); CaptchaOutput = await GenerateCaptchaAsync();
viewModel.CaptchaImageBase64 = GetCaptchaImageBase64(CaptchaOutput.ImageBytes); viewModel.CaptchaImageBase64 = GetCaptchaImageBase64(CaptchaOutput.ImageBytes);
} }
this.Input = viewModel; this.Input = viewModel;
return View("~/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml", this); return View("~/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml", this);
} }
public CaptchaOutput GetCaptcha() public async Task<CaptchaOutput> GenerateCaptchaAsync()
{ {
return SimpleMathsCaptchaGenerator.Generate(new CaptchaOptions( return await SimpleMathsCaptchaGenerator.GenerateAsync(
new CaptchaOptions(
number1MinValue: 1, number1MinValue: 1,
number1MaxValue: 10, number1MaxValue: 10,
number2MinValue: 5, number2MinValue: 5,
number2MaxValue: 15) number2MaxValue: 15
); )
);
} }
public string GetCaptchaImageBase64(byte[] bytes) public string GetCaptchaImageBase64(byte[] bytes)

3
modules/cms-kit/src/Volo.CmsKit.Public.Web/Pages/CmsKit/Shared/Components/Commenting/Default.cshtml

@ -133,7 +133,8 @@
@if (CmsKitCommentOptions.Value.IsRecaptchaEnabled) @if (CmsKitCommentOptions.Value.IsRecaptchaEnabled)
{ {
var output = Model.GetCaptcha(); var output = await Model.GenerateCaptchaAsync();
<div class="volo-captcha"> <div class="volo-captcha">
<label class="form-label" for="Input_Captcha_@output.Id">@L["CaptchaCode"]</label> <label class="form-label" for="Input_Captcha_@output.Id">@L["CaptchaCode"]</label>
<div class="d-flex"> <div class="d-flex">

5
modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaOptions.cs

@ -1,4 +1,5 @@
using SixLabors.Fonts; using System;
using SixLabors.Fonts;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
@ -47,6 +48,8 @@ public class CaptchaOptions
public int Number2MaxValue { get; set; } = 99; public int Number2MaxValue { get; set; } = 99;
public TimeSpan DurationOfValidity { get; set; } = TimeSpan.FromMinutes(10);
public CaptchaOptions() public CaptchaOptions()
{ {

47
modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
@ -15,27 +14,30 @@ using Microsoft.Extensions.Localization;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Color = SixLabors.ImageSharp.Color; using Color = SixLabors.ImageSharp.Color;
using PointF = SixLabors.ImageSharp.PointF; using PointF = SixLabors.ImageSharp.PointF;
using Volo.Abp.Caching;
using Microsoft.Extensions.Caching.Distributed;
namespace Volo.CmsKit.Public.Web.Security.Captcha; namespace Volo.CmsKit.Public.Web.Security.Captcha;
public class SimpleMathsCaptchaGenerator : ISingletonDependency public class SimpleMathsCaptchaGenerator : ITransientDependency
{ {
private readonly IStringLocalizer<CmsKitResource> _localizer; protected IStringLocalizer<CmsKitResource> Localizer { get; }
protected IDistributedCache<CaptchaOutput> Cache { get; }
public SimpleMathsCaptchaGenerator(IStringLocalizer<CmsKitResource> localizer) public SimpleMathsCaptchaGenerator(IStringLocalizer<CmsKitResource> localizer, IDistributedCache<CaptchaOutput> cache)
{ {
_localizer = localizer; Localizer = localizer;
Cache = cache;
} }
private static Dictionary<Guid, CaptchaRequest> Session { get; set; } = new Dictionary<Guid, CaptchaRequest>();
public CaptchaOutput Generate() public virtual Task<CaptchaOutput> GenerateAsync()
{ {
return Generate(options: null, number1: null, number2: null); return GenerateAsync(options: null, number1: null, number2: null);
} }
public CaptchaOutput Generate(CaptchaOptions options) public virtual Task<CaptchaOutput> GenerateAsync(CaptchaOptions options)
{ {
return Generate(options, number1: null, number2: null); return GenerateAsync(options, number1: null, number2: null);
} }
/// <summary> /// <summary>
@ -45,7 +47,7 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency
/// <param name="number1">First number for maths operation</param> /// <param name="number1">First number for maths operation</param>
/// <param name="number2">Second number for maths operation</param> /// <param name="number2">Second number for maths operation</param>
/// <returns></returns> /// <returns></returns>
public CaptchaOutput Generate(CaptchaOptions options, int? number1, int? number2) public virtual async Task<CaptchaOutput> GenerateAsync(CaptchaOptions options, int? number1, int? number2)
{ {
var random = new Random(); var random = new Random();
options ??= new CaptchaOptions(); options ??= new CaptchaOptions();
@ -65,11 +67,15 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency
{ {
Text = text, Text = text,
Result = Calculate(number1.Value, number2.Value), Result = Calculate(number1.Value, number2.Value),
ImageBytes = GenerateInternal(text, options) ImageBytes = GenerateInternal(text, options)
} }
}; };
Session[request.Output.Id] = request; await Cache.SetAsync(request.Output.Id.ToString("N"), request.Output, new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.Add(options.DurationOfValidity)
});
return request.Output; return request.Output;
} }
@ -78,24 +84,25 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency
return number1 + number2; return number1 + number2;
} }
public void Validate(Guid requestId, int value) public virtual async Task ValidateAsync(Guid requestId, int value)
{ {
var request = Session[requestId]; var request = await Cache.GetAsync(requestId.ToString("N"));
if (request.Output.Result != value)
if(request == null || request.Result != value)
{ {
throw new UserFriendlyException(_localizer["CaptchaCodeErrorMessage"]); throw new UserFriendlyException(Localizer["CaptchaCodeErrorMessage"]);
} }
} }
public void Validate(Guid requestId, string value) public virtual async Task ValidateAsync(Guid requestId, string value)
{ {
if (int.TryParse(value, out var captchaInput)) if (int.TryParse(value, out var captchaInput))
{ {
Validate(requestId, captchaInput); await ValidateAsync(requestId, captchaInput);
} }
else else
{ {
throw new UserFriendlyException(_localizer["CaptchaCodeMissingMessage"]); throw new UserFriendlyException(Localizer["CaptchaCodeMissingMessage"]);
} }
} }

Loading…
Cancel
Save