宝塔自助建站系统源码,创意礼物网站建设与管理,湛江网站,公司网站开发费用计入什么科目点击蓝字关注我使用验证码保护网站免受垃圾信息的选择有很多#xff0c;比如Google ReCaptcha和captcha.com。这两者都可以整合到ASP.NET Core应用中去。然而#xff0c;如果你出于某些原因#xff0c;仍然希望自己写验证码#xff0c;例如你下网站需要在中国大陆使用… 点击蓝字关注我使用验证码保护网站免受垃圾信息的选择有很多比如Google ReCaptcha和captcha.com。这两者都可以整合到ASP.NET Core应用中去。然而如果你出于某些原因仍然希望自己写验证码例如你下网站需要在中国大陆使用那么本文会教你如何在最新版的ASP.NET Core中生成和使用验证码。我所使用的方法是在微软样例代码库 https://code.msdn.microsoft.com/How-to-make-and-use-d0d1752a 的基础之上做了一些修改以运行于.NET Core 2.x上并也有一些改进。验证码是如何工作的一个简单的验证码原理是生成一串随机字符数字或字母将字符串保存到Session中同时生成一张图片用来显示在网页上。当用户提交内容到服务器的时服务器检查用户输入的验证码是否与Session中的一致以此判断验证码是否正确。流程如下图这个样例是我下一版本博客中的验证码在 ASP.NET Core 2.1 中实现验证码在了解验证码工作流程之后我们来看看如何实现。1准备工作首先你需要在工程属性的Debug及Release模式里都勾选Allow unsafe code。我们需要使用 System.Drawing.Imaging 命名空间里的类型所以我们也需要安装一个NuGet包Install-Package System.Drawing.Common -Version 4.5.1因为验证码依赖Session存储所以我们也需要在ASP.NET Core中启用Session支持。在Startup.cs里加入public void ConfigureServices(IServiceCollection services){ // other code... // add session support services.AddSession(options { options.IdleTimeout TimeSpan.FromMinutes(20); options.Cookie.HttpOnly true; }); // other code...}还有这里public void Configure(IApplicationBuilder app, IHostingEnvironment env){ // other code... // add session support app.UseSession(); // other code...}注意Session依赖Cookie才能工作所以请确保用户首先接受GDPR cookie策略这是ASP.NET Core 2.1默认模板里添加的。2生成验证码新建一个 CaptchaResult 类用来描述验证码信息public class CaptchaResult{ public string CaptchaCode { get; set; } public byte[] CaptchaByteData { get; set; } public string CaptchBase64Data Convert.ToBase64String(CaptchaByteData); public DateTime Timestamp { get; set; }}以及一个Captcha类来生成并验证验证码public static class Captcha{ const string Letters 2346789ABCDEFGHJKLMNPRTUVWXYZ; public static string GenerateCaptchaCode() { Random rand new Random(); int maxRand Letters.Length - 1; StringBuilder sb new StringBuilder(); for (int i 0; i 4; i) { int index rand.Next(maxRand); sb.Append(Letters[index]); } return sb.ToString(); } public static bool ValidateCaptchaCode(string userInputCaptcha, HttpContext context) { var isValid userInputCaptcha context.Session.GetString(CaptchaCode); context.Session.Remove(CaptchaCode); return isValid; } public static CaptchaResult GenerateCaptchaImage(int width, int height, string captchaCode) { using (Bitmap baseMap new Bitmap(width, height)) using (Graphics graph Graphics.FromImage(baseMap)) { Random rand new Random(); graph.Clear(GetRandomLightColor()); DrawCaptchaCode(); DrawDisorderLine(); AdjustRippleEffect(); MemoryStream ms new MemoryStream(); baseMap.Save(ms, ImageFormat.Png); return new CaptchaResult { CaptchaCode captchaCode, CaptchaByteData ms.ToArray(), Timestamp DateTime.Now }; int GetFontSize(int imageWidth, int captchCodeCount) { var averageSize imageWidth / captchCodeCount; return Convert.ToInt32(averageSize); } Color GetRandomDeepColor() { int redlow 160, greenLow 100, blueLow 160; return Color.FromArgb(rand.Next(redlow), rand.Next(greenLow), rand.Next(blueLow)); } Color GetRandomLightColor() { int low 180, high 255; int nRend rand.Next(high) % (high - low) low; int nGreen rand.Next(high) % (high - low) low; int nBlue rand.Next(high) % (high - low) low; return Color.FromArgb(nRend, nGreen, nBlue); } void DrawCaptchaCode() { SolidBrush fontBrush new SolidBrush(Color.Black); int fontSize GetFontSize(width, captchaCode.Length); Font font new Font(FontFamily.GenericSerif, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); for (int i 0; i captchaCode.Length; i) { fontBrush.Color GetRandomDeepColor(); int shiftPx fontSize / 6; float x i * fontSize rand.Next(-shiftPx, shiftPx) rand.Next(-shiftPx, shiftPx); int maxY height - fontSize; if (maxY 0) maxY 0; float y rand.Next(0, maxY); graph.DrawString(captchaCode[i].ToString(), font, fontBrush, x, y); } } void DrawDisorderLine() { Pen linePen new Pen(new SolidBrush(Color.Black), 3); for (int i 0; i rand.Next(3, 5); i) { linePen.Color GetRandomDeepColor(); Point startPoint new Point(rand.Next(0, width), rand.Next(0, height)); Point endPoint new Point(rand.Next(0, width), rand.Next(0, height)); graph.DrawLine(linePen, startPoint, endPoint); //Point bezierPoint1 new Point(rand.Next(0, width), rand.Next(0, height)); //Point bezierPoint2 new Point(rand.Next(0, width), rand.Next(0, height)); //graph.DrawBezier(linePen, startPoint, bezierPoint1, bezierPoint2, endPoint); } } void AdjustRippleEffect() { short nWave 6; int nWidth baseMap.Width; int nHeight baseMap.Height; Point[,] pt new Point[nWidth, nHeight]; for (int x 0; x nWidth; x) { for (int y 0; y nHeight; y) { var xo nWave * Math.Sin(2.0 * 3.1415 * y / 128.0); var yo nWave * Math.Cos(2.0 * 3.1415 * x / 128.0); var newX x xo; var newY y yo; if (newX 0 newX nWidth) { pt[x, y].X (int)newX; } else { pt[x, y].X 0; } if (newY 0 newY nHeight) { pt[x, y].Y (int)newY; } else { pt[x, y].Y 0; } } } Bitmap bSrc (Bitmap)baseMap.Clone(); BitmapData bitmapData baseMap.LockBits(new Rectangle(0, 0, baseMap.Width, baseMap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); BitmapData bmSrc bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int scanline bitmapData.Stride; IntPtr scan0 bitmapData.Scan0; IntPtr srcScan0 bmSrc.Scan0; unsafe { byte* p (byte*)(void*)scan0; byte* pSrc (byte*)(void*)srcScan0; int nOffset bitmapData.Stride - baseMap.Width * 3; for (int y 0; y nHeight; y) { for (int x 0; x nWidth; x) { var xOffset pt[x, y].X; var yOffset pt[x, y].Y; if (yOffset 0 yOffset nHeight xOffset 0 xOffset nWidth) { if (pSrc ! null) { p[0] pSrc[yOffset * scanline xOffset * 3]; p[1] pSrc[yOffset * scanline xOffset * 3 1]; p[2] pSrc[yOffset * scanline xOffset * 3 2]; } } p 3; } p nOffset; } } baseMap.UnlockBits(bitmapData); bSrc.UnlockBits(bmSrc); bSrc.Dispose(); } } }}这么长的代码你竟然看完了有一些要指出的地方1字符集并不包含全部的字母和数字这是因为有些数字和英文字母难以区分比如数字0和字母O数字5和字母S数字1和字母I2我注释掉了DrawDisorderLine()方法中的贝塞尔曲线这是因为当验证码图片非常小的时候贝塞尔曲线会干扰字符显示看不清验证码。现在在你的MVC控制器中创建一个Action用于返回验证码图片[Route(get-captcha-image)]public IActionResult GetCaptchaImage(){ int width 100; int height 36; var captchaCode Captcha.GenerateCaptchaCode(); var result Captcha.GenerateCaptchaImage(width, height, captchaCode); HttpContext.Session.SetString(CaptchaCode, result.CaptchaCode); Stream s new MemoryStream(result.CaptchaByteData); return new FileStreamResult(s, image/png);}现在尝试访问这个Action你应该能看到像这样的验证码图片3使用验证码在你需要提交内容到服务器端的model里加入一个新的属性叫做CaptchaCode[Required][StringLength(4)]public string CaptchaCode { get; set; }在View中加入一个对应CaptchaCode的输入框以及一个调用GetCaptchaImage的图片div classinput-group div classinput-group-prepend img idimg-captcha data-src~/get-captcha-image / /div input typetext classform-control placeholderCaptcha Code asp-forCaptchaCode maxlength4 / span asp-validation-forCaptchaCode classtext-danger/span/div在处理用户提交数据的Action中加入检查验证码的逻辑if (ModelState.IsValid){ // Validate Captcha Code if (!Captcha.ValidateCaptchaCode(model.CaptchaCode, HttpContext)) { // return error } // continue business logic}4再完善一点你可以用jQuery实现用户点击图片刷新验证码$(#img-captcha).click(function () { resetCaptchaImage();});function resetCaptchaImage() { d new Date(); $(#img-captcha).attr(src, /get-captcha-image? d.getTime());}