update
This commit is contained in:
1 parent
9cc95215ff
commit
69059b2e64
5 files changed
+48
-27
No files matched your search
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<PackageId>CaptchaKit.AspNetCore</PackageId>
|
||||
<Version>0.1.0-preview.2</Version>
|
||||
<Version>0.1.0-preview.3</Version>
|
||||
<Authors>CaptchaKit Contributors</Authors>
|
||||
<Description>ASP.NET Core and distributed-cache integration for CaptchaKit.</Description>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
|
||||
@@ -13,7 +13,7 @@ public sealed class CaptchaKitOptions
|
||||
public TimeSpan Lifetime { get; set; } = TimeSpan.FromMinutes(2);
|
||||
public string CacheKeyPrefix { get; set; } = "captchakit:";
|
||||
public bool RequireBrowserProof { get; set; }
|
||||
public bool EnableOneClickChallenge { get; set; } = true;
|
||||
public bool EnableMathChallenge { get; set; } = true;
|
||||
public bool EnableSelectionChallenge { get; set; } = true;
|
||||
}
|
||||
|
||||
@@ -85,33 +85,41 @@ public sealed class DistributedCaptchaChallengeStore(
|
||||
public sealed class RandomCaptchaGenerator(CaptchaKitOptions options) : ICaptchaGenerator
|
||||
{
|
||||
private readonly SkiaTextCaptchaGenerator _text = new();
|
||||
private const string SelectionAlphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
|
||||
public GeneratedCaptcha Generate(CaptchaGenerationRequest request)
|
||||
{
|
||||
var roll = RandomNumberGenerator.GetInt32(100);
|
||||
if (options.EnableOneClickChallenge && roll < 15)
|
||||
if (options.EnableMathChallenge && roll < 25)
|
||||
{
|
||||
return new GeneratedCaptcha(
|
||||
new CaptchaChallenge(request.Id, CaptchaChallengeType.OneClick, request.ExpiresAt,
|
||||
"请点击确认按钮继续登录"),
|
||||
"CONFIRM");
|
||||
var left = RandomNumberGenerator.GetInt32(2, 10);
|
||||
var right = RandomNumberGenerator.GetInt32(1, 10);
|
||||
var isAddition = RandomNumberGenerator.GetInt32(2) == 0;
|
||||
if (!isAddition && right > left)
|
||||
(left, right) = (right, left);
|
||||
var expression = $"{left} {(isAddition ? '+' : '-')} {right} = ?";
|
||||
var answer = (isAddition ? left + right : left - right).ToString();
|
||||
return _text.CreateVisualChallenge(
|
||||
request, expression, answer, CaptchaChallengeType.MathImage, "请计算图片中的算式");
|
||||
}
|
||||
if (options.EnableSelectionChallenge && roll < 45)
|
||||
if (options.EnableSelectionChallenge && roll < 55)
|
||||
{
|
||||
var correct = RandomNumberGenerator.GetInt32(2, 10).ToString();
|
||||
var candidates = Enumerable.Range(1, 9)
|
||||
.Where(x => x.ToString() != correct)
|
||||
var target = SelectionAlphabet[RandomNumberGenerator.GetInt32(SelectionAlphabet.Length)].ToString();
|
||||
var candidates = SelectionAlphabet
|
||||
.Select(x => x.ToString())
|
||||
.Where(x => x != target)
|
||||
.OrderBy(_ => RandomNumberGenerator.GetInt32(int.MaxValue))
|
||||
.Take(3)
|
||||
.Append(int.Parse(correct))
|
||||
.Append(target)
|
||||
.OrderBy(_ => RandomNumberGenerator.GetInt32(int.MaxValue))
|
||||
.Select(x => new CaptchaChoice($"choice-{x}", x.ToString()))
|
||||
.Select(x => new CaptchaChoice($"choice-{x}", x))
|
||||
.ToList();
|
||||
var answer = candidates.Single(x => x.Label == correct).Id;
|
||||
var answer = candidates.Single(x => x.Label == target).Id;
|
||||
var visual = _text.CreateVisualChallenge(
|
||||
request, target, answer, CaptchaChallengeType.Selection, "请选择与图片中字符相同的一项");
|
||||
return new GeneratedCaptcha(
|
||||
new CaptchaChallenge(request.Id, CaptchaChallengeType.Selection, request.ExpiresAt,
|
||||
$"请选择数字 {correct}", candidates),
|
||||
answer);
|
||||
visual.Challenge with { Choices = candidates },
|
||||
visual.Answer);
|
||||
}
|
||||
return _text.Generate(request);
|
||||
}
|
||||
@@ -125,27 +133,39 @@ public sealed class SkiaTextCaptchaGenerator : ICaptchaGenerator
|
||||
{
|
||||
var answer = string.Concat(Enumerable.Range(0, request.CodeLength)
|
||||
.Select(_ => Alphabet[RandomNumberGenerator.GetInt32(Alphabet.Length)]));
|
||||
using var bitmap = new SKBitmap(160, 54);
|
||||
return CreateVisualChallenge(request, answer, answer, CaptchaChallengeType.TextImage, "请输入图中的字符");
|
||||
}
|
||||
|
||||
public GeneratedCaptcha CreateVisualChallenge(
|
||||
CaptchaGenerationRequest request,
|
||||
string displayText,
|
||||
string answer,
|
||||
CaptchaChallengeType type,
|
||||
string prompt)
|
||||
{
|
||||
var width = Math.Max(160, 20 + displayText.Length * 27);
|
||||
using var bitmap = new SKBitmap(width, 54);
|
||||
using var canvas = new SKCanvas(bitmap);
|
||||
canvas.Clear(new SKColor(244, 248, 252));
|
||||
DrawNoise(canvas, 160, 54, 13);
|
||||
DrawNoise(canvas, width, 54, 16);
|
||||
using var paint = new SKPaint { IsAntialias = true };
|
||||
using var font = new SKFont(SKTypeface.FromFamilyName("Arial", SKFontStyle.Bold), 30);
|
||||
for (var index = 0; index < answer.Length; index++)
|
||||
var spacing = Math.Max(22, (width - 24) / displayText.Length);
|
||||
for (var index = 0; index < displayText.Length; index++)
|
||||
{
|
||||
var x = 14 + index * 29 + RandomNumberGenerator.GetInt32(-2, 3);
|
||||
var x = 12 + index * spacing + RandomNumberGenerator.GetInt32(-2, 3);
|
||||
var y = 38 + RandomNumberGenerator.GetInt32(-4, 5);
|
||||
paint.Color = RandomColor(35, 145);
|
||||
canvas.Save();
|
||||
canvas.RotateDegrees(RandomNumberGenerator.GetInt32(-20, 21), x, y);
|
||||
canvas.DrawText(answer[index].ToString(), x, y, SKTextAlign.Left, font, paint);
|
||||
canvas.DrawText(displayText[index].ToString(), x, y, SKTextAlign.Left, font, paint);
|
||||
canvas.Restore();
|
||||
}
|
||||
DrawNoise(canvas, 160, 54, 8);
|
||||
DrawNoise(canvas, width, 54, 10);
|
||||
using var image = SKImage.FromBitmap(bitmap);
|
||||
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
|
||||
var challenge = new CaptchaChallenge(request.Id, CaptchaChallengeType.TextImage, request.ExpiresAt,
|
||||
"请输入图中的字符", null, "image/png", data.ToArray());
|
||||
var challenge = new CaptchaChallenge(request.Id, type, request.ExpiresAt,
|
||||
prompt, null, "image/png", data.ToArray());
|
||||
return new GeneratedCaptcha(challenge, answer);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user