.netCore 图形验证码,非System.Drawing.Common
netcore需要跨平台,说白点就是放在windows服务器要能用,放在linux服务器上也能用,甚至macos上。
很多时候需要使用到图形验证码,这就有问题了。
旧方案
1.引入包
<PackageReference Include="System.Drawing.Common" Version="5.0.3" />
2.添加引用
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
3.在linux上安装libgdiplus
问题在于这个libgdiplus东西非常大,这个东西是moon兼容而来的,而且!!!.net6.0开始不支持这个东西了。
新方案
1.安装包
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
要勾选预览版,不然找不到这个包
2.添加引用
using SixLabors.Fonts; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing;
3.生成一个验证码图片
public byte[] CreateByteByImgVerifyCode(string verifyCode, int width, int height) { using Image image = new Image<Rgba32>(width, height); //漆底色白色 image.Mutate(x => x.DrawLines(Pens.DashDot(Color.White, width), new PointF[] { new PointF() { X = 0, Y = 0 }, new PointF() { X = width, Y = height } })); FontCollection collection = new(); FontFamily family = collection.Add("font/font.ttf"); Font font = family.CreateFont(20, FontStyle.Bold); PointF startPointF = new PointF(5, 5); Random random = new Random(); //随机数产生器 Color[] colors = new Color[] { Color.Red, Color.Blue, Color.Green, Color.Purple, Color.Peru, Color.LightSeaGreen, Color.Lime, Color.Magenta, Color.Maroon, Color.MediumBlue, Color.MidnightBlue, Color.Navy }; //绘制大小 for (int i = 0; i < verifyCode.Length; i++) { image.Mutate(x => x.DrawText(verifyCode[i].ToString(), font, colors[random.Next(colors.Length)], startPointF)); //Console.WriteLine($"draw code:{verifyCode[i]} point:{startPointF.X}-{startPointF.Y}"); startPointF.X += (int)(width - 10) / verifyCode.Length; startPointF.Y = random.Next(5, 10); } IPen pen = Pens.DashDot(Color.Silver, 1); //绘制干扰线 for (var k = 0; k < 40; k++) { PointF[] points = new PointF[2]; points[0] = new PointF(random.Next(width), random.Next(height)); points[1] = new PointF(random.Next(width), random.Next(height)); image.Mutate(x => x.DrawLines(pen, points)); } using MemoryStream stream = new MemoryStream(); image.Save(stream, JpegFormat.Instance); //输出图片流 return stream.ToArray(); }
4.在controller中调用它
[HttpGet] public FileContentResult Code(string guid) { try { if (String.IsNullOrEmpty(guid)) { throw new Exception("验证码代码错误,guid不能为空!"); } //进行特殊符号的替换工作 if (!new System.Text.RegularExpressions.Regex("[0-9,a-z,A-Z]{16}").Match(guid).Success) { throw new Exception("guid的位数不足,应为16位随机数,不能包含特殊符号,需要为字母和数字的组合"); } if (_cache.KeyExits(string.Format(PublicString.CacheImageHead, guid))) { throw new Exception("guid不能重复使用!"); } //判断guid是否存在 string code = _imgHelper.CreateVerifyCode(ImageHelper.VerifyCodeType.NumberVerifyCode); _cache.SetString(string.Format(PublicString.CacheImageHead, guid), code, 300); byte[] codeImage = _imgHelper.CreateByteByImgVerifyCode(code, 80, 36); return File(codeImage, @"image/jpeg"); } catch (Exception exl) { _logger.LogException(exl); throw new Exception(exl.Message); } }
5.随机数计算,缓存帮助类自己实现。
6.新方案不需要安装libgdiplus
7.旧方案占用内存很大,新方案内存消耗很划算
附上一个Dockerfile的文件内容
FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base # 安装tzdata RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories RUN apk add --no-cache tzdata #RUN apk add libgdiplus --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ --allow-untrusted #RUN apk add terminus-font # 设置时区 ENV TZ="Asia/Shanghai" ENV LANG C.UTF-8 FROM base AS final WORKDIR /app EXPOSE 80 COPY . . ENTRYPOINT ["dotnet", "xxx.HttpApi.Host.dll"]
当前为草稿,暂未完善