推荐用ImageSharp而非System.Drawing,因其跨平台且无需额外依赖;需正确启用Session、禁用图片缓存、统一字符串处理以避免校验失败。

验证码图片生成要用 System.Drawing 还是 ImageSharp?
在 .NET 6+ 环境下,System.Drawing 在 Linux/macOS 容器中默认不可用(会抛 System.PlatformNotSupportedException),强行启用需安装额外 native 依赖,部署麻烦。推荐直接用跨平台的 ImageSharp(v2+)。
实操建议:
- 通过
dotnet add package SixLabors.ImageSharp引入 - 生成 200×80 像素 PNG 图片,避免使用高分辨率或透明通道(部分前端 img 标签对 alpha 渲染不一致)
- 字符选 4–6 位,只用大小写字母 + 数字(避开 0/O/l/1 等易混淆字符)
- 叠加 2–3 条干扰线 + 轻微噪点,但别过度——OCR 工具仍可能绕过,靠的是增加自动化识别成本,不是绝对防破解
HttpContext.Session 存验证码值时为什么总为空?
Session 默认未启用,且必须在中间件顺序中位于 UseRouting 之后、UseEndpoints 之前。常见错误是漏掉 AddSession() 或调用顺序错。
实操建议:
- 在
Program.cs中添加:builder.Services.AddSession(options => options.IdleTimeout = TimeSpan.FromMinutes(5)); - 在
app.UseSession();必须放在app.UseRouting();之后、app.UseEndpoints(...);之前 - 存值用:
HttpContext.Session.SetString("captcha_code", code);,取值前先判空:HttpContext.Session.GetString("captcha_code")可能返回null(超时或未生成)
前端刷新验证码图片但不触发新请求?
浏览器缓存了 的响应,导致点击刷新时还是旧图。这不是后端问题,是 HTTP 缓存策略没控制好。
实操建议:
- 后端返回图片时加响应头:
context.Response.Headers.Append("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); - 前端刷新逻辑不要只改
img.src,要加时间戳参数:img.src = '/captcha?' + Date.now(); - 避免用
location.reload()模拟刷新——它重载整个页面,体验差,也不解决本质缓存问题
校验时提示“验证码错误”但明明输对了?
大小写敏感、前后空格、全角字符混入是高频原因。Session 中存的是原始生成字符串(如 "K7mP"),而用户输入可能带空格、粘贴进全角字母、或浏览器自动转义了某些字符。
实操建议:
- 后端校验前统一处理:
input.Trim().Replace(" ", "").ToUpperInvariant() - Session 中存的码也建议转成大写并去空格,保持两端一致
- 调试时先打印 Session 里的值和用户提交值的
Length和char数组,比单纯看字符串更可靠 - 别在验证码校验后立即清除 Session 值——万一用户输错一次还想再试,清得太早会导致第二次必错
验证码的核心不是“绝对安全”,而是让批量注册/登录脚本的成本显著高于人工操作。真正需要高安全的场景(如金融操作确认),该上短信或 WebAuthn,而不是堆图形复杂度。











