.NET 5 原生验证码生成

“原生”体现在不使用第三方组件或服务,使用了 System.Drawing

下文将展示如何在 .NET 5 默认 MVC 模板中添加验证码功能

去夜之城旅游了11

环境

  • .NET 5
  • Windows 10
  • Visual Studio 2019

参考

步骤

代码几乎大部分来自参考链接,在参考基础上略有删改

Nuget 安装组件

.NET 5 默认不包含 Bitmap(位于 System.Drawing.Common),需要使用 Nuget 安装

Install-Package System.Drawing.Common -Version 5.0.0

# dotnet add package System.Drawing.Common --version 5.0.0

.NET 5 原生验证码生成

添加接口

添加 ICaptcha 接口

public interface ICaptcha {
    Task<string> GenerateRandomCaptchaAsync(int codelength = 4);
    Task<CaptchaResult> GenerateCaptchaImageAsync(string captchaCode, int width = 0, int height = 30);
}

添加验证码模型

Captcha 模型包含验证码字符串、验证码图片(MemoryStream 形式保存)和时间戳

//using ...
using System.IO;

public class CaptchaResult { 
    public string CaptchaCode { get; set; }
    public MemoryStream CaptchaMemoryStream { get; set; }
    public DateTime TimeStamp { get; set; }
}

实现接口

实现接口中的验证码字符串生成和验证码转图片方法

public class Captcha : ICaptcha {
    private const string Letters = "1,2,3,4,5,6,7,8,9,0,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";

    public Task<string> GenerateRandomCaptchaAsync(int codelength = 4) {
        var array = Letters.Split(",");

        var rd = new Random();

        var temp = -1;

        var captchaCode = string.Empty;

        for (int i = 0; i < codelength; i++) {
            if (temp != -1)
                rd = new Random(i * temp * unchecked((int)DateTime.Now.Ticks));

            var index = rd.Next(array.Length);

            if (temp != -1 && temp == index)
                return GenerateRandomCaptchaAsync(codelength);

            temp = index;

            captchaCode += array[index];
        }

        return Task.FromResult(captchaCode);
    }
    
    public Task<CaptchaResult> GenerateCaptchaImageAsync(string captchaCode, int width = 0, int height = 30) {
        Color[] c = { Color.Black, Color.Red, Color.Green, Color.Cyan, Color.DarkBlue, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };

        string[] fonts = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial" };

        var image = new Bitmap(width == 0 ? captchaCode.Length * 25 : width, height);

        var g = Graphics.FromImage(image);

        g.Clear(Color.White);

        var random = new Random();

        for (int i = 0; i < 100; i++) {
            var x = random.Next(image.Width);
            var y = random.Next(image.Height);
            g.DrawRectangle(new Pen(Color.LightGray, 0), x, y, 1, 1);
        }

        for (int i = 0; i < 4; i++) {
            var cindex = random.Next(c.Length);
            var findex = random.Next(fonts.Length);

            var f = new Font(fonts[findex], 15, FontStyle.Bold);

            Brush b = new SolidBrush(c[cindex]);

            var ii = 4;
            if ((i + 1) % 2 == 0)
                ii = 2;

            g.DrawString(captchaCode.Substring(i, 1), f, b, 17 + (i * 17), ii);
        }

        var ms = new MemoryStream();
        image.Save(ms, ImageFormat.Png);

        g.Dispose();
        image.Dispose();

        return Task.FromResult(new CaptchaResult {
            CaptchaCode = captchaCode,
            CaptchaMemoryStream = ms,
            TimeStamp = DateTime.Now
        });
    }
}

调用

在模板默认的 Home 控制器中调用

[Route("captcha")]
public async Task<FileContentResult> CapchaAsync() {
    var captcha = new Captcha();

    var code = await captcha.GenerateRandomCaptchaAsync();

    _logger.LogInformation("Captcha code is: {0}", code);

    var result = await captcha.GenerateCaptchaImageAsync(code);

    return File(result.CaptchaMemoryStream.ToArray(), "image/png");
}

效果

.NET 5 原生验证码生成.NET 5 原生验证码生成

 

发表评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据