You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

78 lines
2.5 KiB

using CellularManagement.Domain.Services;
using SkiaSharp;
namespace CellularManagement.Infrastructure.Services.Security;
public class CaptchaService : ICaptchaService
{
private readonly Random _random = new();
private readonly string[] _fonts = { "Arial", "Verdana", "Times New Roman", "Tahoma" };
private readonly SKColor[] _colors = {
SKColors.Black, SKColors.Red, SKColors.Blue, SKColors.Green, SKColors.Purple, SKColors.Orange
};
public (string Code, byte[] ImageBytes) GenerateCaptcha(int length = 4)
{
string code = GenerateRandomCode(length);
int width = Math.Max(120, 10 + length * 25);
int height = 40;
using var bitmap = new SKBitmap(width, height);
using var canvas = new SKCanvas(bitmap);
canvas.Clear(SKColors.White);
// 干扰线
for (int i = 0; i < 5; i++)
{
using var paint = new SKPaint
{
Color = _colors[_random.Next(_colors.Length)],
StrokeWidth = 1
};
canvas.DrawLine(
_random.Next(width), _random.Next(height),
_random.Next(width), _random.Next(height),
paint
);
}
// 干扰点
for (int i = 0; i < 100; i++)
{
using var paint = new SKPaint
{
Color = _colors[_random.Next(_colors.Length)],
StrokeWidth = 1
};
canvas.DrawPoint(_random.Next(width), _random.Next(height), paint);
}
// 绘制验证码字符
for (int i = 0; i < code.Length; i++)
{
using var paint = new SKPaint
{
Color = _colors[_random.Next(_colors.Length)],
TextSize = 24,
IsAntialias = true,
Typeface = SKTypeface.FromFamilyName(_fonts[_random.Next(_fonts.Length)], SKFontStyle.Bold)
};
float x = 10 + i * 25;
float y = 30 + _random.Next(-5, 5);
canvas.DrawText(code[i].ToString(), x, y, paint);
}
using var ms = new MemoryStream();
using var image = SKImage.FromBitmap(bitmap);
image.Encode(SKEncodedImageFormat.Png, 100).SaveTo(ms);
return (code, ms.ToArray());
}
private string GenerateRandomCode(int length)
{
const string chars = "2345678ABCDEFGHJKLMNPQRSTUVWXYZ";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[_random.Next(s.Length)]).ToArray());
}
}