ASP.NET Core:带3分钟时效与请求限制的登录激活码实现
在ASP.NET Core中实现登录激活码功能
核心设计目标
- 验证码仅3分钟内有效,到期自动失效
- 同一用户在有效期内无法重复请求新验证码
- 验证码与用户标识(手机号/邮箱/用户ID)绑定,避免跨用户复用
实现步骤
1. 选择缓存存储方案
使用ASP.NET Core自带的IDistributedCache(推荐,支持多实例部署)或IMemoryCache(单实例场景够用),用于存储验证码及过期时间。
2. 验证码生成与管理服务
创建核心服务类,封装验证码的生成、发送限制、验证逻辑:
public class VerificationCodeService { private readonly IDistributedCache _cache; private const string CacheKeyPrefix = "LoginVerification_"; private const int CodeExpireMinutes = 3; public VerificationCodeService(IDistributedCache cache) { _cache = cache; } // 检查用户是否可以请求新验证码 public async Task<bool> IsCodeRequestAllowedAsync(string userIdentifier) { var cacheKey = $"{CacheKeyPrefix}{userIdentifier}"; var existingCode = await _cache.GetStringAsync(cacheKey); return string.IsNullOrEmpty(existingCode); } // 生成并发送验证码(替换为真实短信/邮箱逻辑) public async Task SendCodeAsync(string userIdentifier) { if (!await IsCodeRequestAllowedAsync(userIdentifier)) throw new InvalidOperationException("验证码未过期,请勿重复请求"); var verificationCode = GenerateRandomCode(6); // 👇 这里替换为调用短信/邮箱API的实际代码 Console.WriteLine($"向 {userIdentifier} 发送登录验证码:{verificationCode}"); // 将验证码存入缓存,设置3分钟过期 await _cache.SetStringAsync( $"{CacheKeyPrefix}{userIdentifier}", verificationCode, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CodeExpireMinutes) }); } // 验证验证码有效性 public async Task<bool> VerifyCodeAsync(string userIdentifier, string inputCode) { var cacheKey = $"{CacheKeyPrefix}{userIdentifier}"; var storedCode = await _cache.GetStringAsync(cacheKey); if (storedCode == null || !storedCode.Equals(inputCode, StringComparison.Ordinal)) return false; // 验证成功后立即删除缓存,防止重复使用 await _cache.RemoveAsync(cacheKey); return true; } // 生成指定长度的随机数字验证码 private string GenerateRandomCode(int length) { var random = new Random(); return new string(Enumerable.Repeat("0123456789", length) .Select(s => s[random.Next(s.Length)]).ToArray()); } }
3. 注册服务
在Program.cs中注册缓存和自定义服务:
// 注册分布式内存缓存(生产环境建议替换为Redis) builder.Services.AddDistributedMemoryCache(); // 注册验证码服务 builder.Services.AddScoped<VerificationCodeService>();
4. 编写API接口
创建控制器处理验证码请求与登录验证:
[ApiController] [Route("api/auth")] public class AuthController : ControllerBase { private readonly VerificationCodeService _codeService; public AuthController(VerificationCodeService codeService) { _codeService = codeService; } // 请求登录验证码 [HttpPost("send-verification-code")] public async Task<IActionResult> SendVerificationCode([FromBody] CodeRequestDto request) { try { await _codeService.SendCodeAsync(request.UserIdentifier); return Ok(new { Message = "验证码已发送,3分钟内有效" }); } catch (InvalidOperationException ex) { return BadRequest(new { Message = ex.Message }); } } // 使用验证码登录 [HttpPost("login-with-code")] public async Task<IActionResult> LoginWithCode([FromBody] CodeLoginDto request) { var isCodeValid = await _codeService.VerifyCodeAsync(request.UserIdentifier, request.Code); if (!isCodeValid) return Unauthorized(new { Message = "验证码无效或已过期" }); // 👇 这里添加生成JWT令牌或创建登录会话的逻辑 return Ok(new { Message = "登录成功", Token = "your-jwt-token-here" }); } } // 请求DTO public class CodeRequestDto { public string UserIdentifier { get; set; } // 手机号/邮箱/用户ID } public class CodeLoginDto { public string UserIdentifier { get; set; } public string Code { get; set; } }
生产环境优化建议
- 替换模拟发送逻辑为真实的短信/邮箱服务商API(如阿里云短信、SendGrid)
- 添加验证码错误次数限制(如连续3次输错后锁定5分钟)
- 若部署多实例,改用Redis等分布式缓存替代内存缓存
- 对用户标识进行加密存储,避免明文泄露风险
内容的提问来源于stack exchange,提问作者Hossein
相关产品推荐
相关产品推荐

