加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_阳江站长网 (https://www.0662zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > Asp教程 > 正文

ASP.NET Core 生成验证码

发布时间:2022-12-05 12:39:06 所属栏目:Asp教程 来源:
导读:  使用验证码保护网站免受垃圾信息的选择有很多,比如Google ReCaptcha和captcha.com。这两者都可以整合到ASP.NET Core应用中去。然而,如果你出于某些原因,仍然希望自己写验证码,例如你下网站需要在中国大陆使用
  使用验证码保护网站免受垃圾信息的选择有很多,比如Google ReCaptcha和captcha.com。这两者都可以整合到ASP.NET Core应用中去。然而,如果你出于某些原因,仍然希望自己写验证码,例如你下网站需要在中国大陆使用,那么本文会教你如何在最新版的ASP.NET Core中生成和使用验证码。
 
  我所使用的方法是在微软样例代码库 的基础之上做了一些修改,以运行于.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验证码,所以我们也需要在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默认模板里添加的。
 
  [asp.net mvc4]验证用户登录实现_asp验证码_asp.net mvc form验证
 
  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;
 
  [asp.net mvc4]验证用户登录实现_asp验证码_asp.net mvc form验证
 
  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();
 
  }
 
  }
 
  }
 
  }
 
  这么长的代码你竟然看完了!
 
  [asp.net mvc4]验证用户登录实现_asp验证码_asp.net mvc form验证
 
  有一些要指出的地方:
 
  1
 
  字符集并不包含全部的字母和数字,这是因为有些数字和英文字母难以区分,比如:
 
  2
 
  我注释掉了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,你应该能看到像这样的验证码图片:
 
  [asp.net mvc4]验证用户登录实现_asp验证码_asp.net mvc form验证
 
  3
 
  使用验证码
 
  在你需要提交内容到服务器端的model里加入一个新的属性,叫做CaptchaCode
 
  [Required]
 
  [StringLength(4)]
 
  public string CaptchaCode { get; set; }
 
  在View中加入一个对应CaptchaCode的输入框,以及一个调用GetCaptchaImage的图片
 
  在处理用户提交数据的Action中加入检查验证码的逻辑
 
  if (ModelState.IsValid)
 
  {
 
  // Validate Captcha Code
 
  if (!Captcha.ValidateCaptchaCode(model.CaptchaCode, HttpContext))
 
  {
 
  // return error
 
  }
 
  // continue business logic
 
  }
 
  asp验证码_asp.net mvc form验证_[asp.net mvc4]验证用户登录实现
 
  4
 
  再完善一点
 
  你可以用jQuery实现用户点击图片刷新验证码
 
  $("#img-captcha").click(function () {
 
  resetCaptchaImage();
 
  });
 
  function resetCaptchaImage() {
 
  d = new Date();
 
  $("#img-captcha").attr("src", "/get-captcha-image?" + d.getTime());
 
  }
 
 
 

(编辑:应用网_阳江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!