You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在搭载IdentityServer的ASP.NET Core 5.0应用中实现验证码功能

基于ASP.NET Core Identity + IdentityServer4的验证码实现方案

1. 前置准备

验证码一般需要添加在注册、登录、密码重置等敏感用户操作节点,正式开发前需要先完成以下准备:

  • 用Identity脚手架导出默认UI页面,方便自定义表单和处理逻辑,脚手架命令为:dotnet aspnet-codegenerator identity -dc 你的项目DbContext名称
  • 准备分布式缓存组件(如Redis)存储验证码状态,多实例部署场景禁止使用内存缓存,会导致跨实例验证码校验失败
  • 按需选择实现方案:自定义图形Captcha(完全可控、无外部依赖)或者Google reCAPTCHA(开发量小、防爬虫效果更好)

2. 自定义图形Captcha实现步骤

2.1 安装依赖包

推荐使用SixLabors.ImageSharp做图形绘制,执行命令安装:dotnet add package SixLabors.ImageSharp

2.2 封装验证码服务

新增ICaptchaService接口和对应实现类,核心逻辑包含生成和校验两个方法:

// 验证码生成方法
public async Task<(string CaptchaId, byte[] ImageData)> GenerateAsync(int length = 4, int width = 120, int height = 40)
{
    // 生成4位随机验证码(可自定义规则,比如纯数字、字母+数字组合)
    var captchaCode = new Random().Next(1000, 9999).ToString();
    var captchaId = Guid.NewGuid().ToString("N");
    // 验证码存入分布式缓存,有效期5分钟
    await _distributedCache.SetStringAsync($"captcha:{captchaId}", captchaCode, new DistributedCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
    });
    // 用ImageSharp绘制带噪点、干扰线的验证码图片,返回PNG字节流
    using var image = new Image<Rgba32>(width, height);
    // 省略图片绘制逻辑(填充背景、写验证码文字、加干扰元素)
    var imageBytes = image.SaveAsPngBytes();
    return (captchaId, imageBytes);
}

// 验证码校验方法
public async Task<bool> ValidateAsync(string captchaId, string inputCode)
{
    var cacheKey = $"captcha:{captchaId}";
    var storedCode = await _distributedCache.GetStringAsync(cacheKey);
    if (storedCode == null || !storedCode.Equals(inputCode, StringComparison.OrdinalIgnoreCase))
        return false;
    // *校验通过立即删除缓存,防止同一个验证码被重复恶意使用*
    await _distributedCache.RemoveAsync(cacheKey);
    return true;
}

在Program.cs中注册服务:builder.Services.AddScoped<ICaptchaService, CaptchaService>();

2.3 新增验证码获取接口

新增Controller提供验证码图片访问入口:

[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> GetCaptcha()
{
    var (captchaId, imageData) = await _captchaService.GenerateAsync();
    // 验证码ID存入HttpOnly Cookie,防止前端篡改
    Response.Cookies.Append("captcha_id", captchaId, new CookieOptions
    {
        HttpOnly = true,
        Secure = true,
        SameSite = SameSiteMode.Strict,
        Expires = DateTimeOffset.UtcNow.AddMinutes(5)
    });
    return File(imageData, "image/png");
}

2.4 修改Identity页面表单和处理逻辑

  • 在注册/登录页面的表单中添加验证码输入框和图片展示:
<div class="form-group">
    <label>请输入验证码</label>
    <div class="d-flex align-items-center gap-2">
        <input asp-for="Input.Captcha" class="form-control" autocomplete="off" />
        <img src="/Account/GetCaptcha" id="captchaImg" style="cursor:pointer;height:38px" alt="验证码" title="点击刷新">
    </div>
    <span asp-validation-for="Input.Captcha" class="text-danger"></span>
</div>
<script>
// 点击刷新验证码
document.getElementById('captchaImg').addEventListener('click', function() {
    this.src = '/Account/GetCaptcha?t=' + new Date().getTime();
});
</script>
  • 在对应PageModel的Post处理逻辑开头添加校验:
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    var captchaId = Request.Cookies["captcha_id"];
    var isValid = await _captchaService.ValidateAsync(captchaId, Input.Captcha);
    if (!isValid)
    {
        ModelState.AddModelError(string.Empty, "验证码错误或已过期");
        return Page();
    }
    // 原有Identity注册/登录逻辑保留
}

3. reCAPTCHA实现步骤

如果不想自己维护图形验证码逻辑,可以直接接入reCAPTCHA:

  1. 申请reCAPTCHA的站点密钥(SiteKey)和服务端密钥(SecretKey),存入appsettings.json
  2. 前端表单中引入reCAPTCHA组件,提交时会自动生成g-recaptcha-response参数
  3. 服务端在Post处理逻辑中拿到该参数,向reCAPTCHA校验接口发起请求验证即可,reCAPTCHA v3不需要用户手动点击,会自动根据用户行为打分,可根据业务场景调整校验阈值

4. IdentityServer4兼容注意事项

  • 若要修改IdentityServer4的授权页面(登录、同意授权页),修改逻辑和上述Identity页面完全一致,直接导出IdentityServer4的UI源码后添加校验即可
  • 不要将验证码校验逻辑加入Identity的密码验证器中,避免影响ClientCredentials等无需用户交互的OAuth授权模式
  • 若需要给受IdentityServer4保护的业务接口加验证码,直接在对应接口层添加校验逻辑即可,无需修改IdentityServer4核心配置

内容的提问来源于stack exchange,提问作者Boppity Bop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 18:15:04