ASP.NET 3.1 Web API中如何将JWT令牌保存至数据库?
解决JWT令牌保存到数据库的问题
一、先修复现有代码的核心问题
1. 完善AuthenticationToken模型
当前模型缺少主键(EF Core要求实体必须有主键),且未关联用户,无法区分令牌归属。修改后:
public class AuthenticationToken { // EF Core自动识别Id为主键 public int Id { get; set; } public string Token { get; set; } // 关联用户的外键 public int UserId { get; set; } // 导航属性,关联到用户实体 public Register User { get; set; } // 新增:记录令牌过期时间,方便后续清理过期数据 public DateTime ExpiresAt { get; set; } }
2. 调整JwtAuthContext上下文
Login是登录请求的DTO(仅用于接收请求参数),无需存入数据库,移除冗余的DbSet<Login>:
public class JwtAuthContext : DbContext { public JwtAuthContext(DbContextOptions<JwtAuthContext> options) : base(options) { } public DbSet<Register> Registers { get; set; } // 规范命名,首字母大写 public DbSet<AuthenticationToken> AuthenticationTokens { get; set; } // 显式配置外键关系,避免EF Core自动映射出错 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AuthenticationToken>() .HasOne(t => t.User) .WithMany() .HasForeignKey(t => t.UserId) .OnDelete(DeleteBehavior.Cascade); // 删除用户时自动清理关联令牌 } }
3. 修改LoginController的Login方法,实现令牌保存
生成令牌后,创建AuthenticationToken实例并添加到上下文,完成数据库存储:
[HttpPost] public IActionResult Login([FromBody] Login login) { var user = Authenticate(login); if (user != null) { var tokenString = Generate(user); // 解析令牌获取过期时间 var tokenHandler = new JwtSecurityTokenHandler(); var jwtToken = tokenHandler.ReadJwtToken(tokenString); // 构造令牌实体 var authToken = new AuthenticationToken { Token = tokenString, UserId = user.Id, ExpiresAt = jwtToken.ValidTo }; _context.AuthenticationTokens.Add(authToken); _context.SaveChanges(); // 关键步骤:将令牌写入数据库 return Ok(new { Token = tokenString }); } return NotFound("用户不存在"); }
4. 修正Generate方法的Claim映射错误
当前Claim类型与内容不匹配,修正后更符合规范:
private string Generate(Register user) { var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var claims = new[] { new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), // 存储用户ID而非Email new Claim(ClaimTypes.Email, user.Email), // Email对应ClaimTypes.Email new Claim(ClaimTypes.Name, user.FullName), // 用户名对应ClaimTypes.Name new Claim(ClaimTypes.Role, user.Role ?? "User") // 处理Role为空的默认值 }; var token = new JwtSecurityToken( _config["Jwt:Issuer"], _config["Jwt:Audience"], claims, expires: DateTime.Now.AddMinutes(15), signingCredentials: credentials); return new JwtSecurityTokenHandler().WriteToken(token); }
二、现有代码的其他风险提醒
- 密码明文存储:当前注册直接存储明文密码,极易泄露,必须使用BCrypt、ASP.NET Core Identity的
PasswordHasher等工具哈希后再存储。 - 令牌过期清理:数据库中会累积大量过期令牌,建议定时执行清理任务(比如用Hangfire或后台服务)删除
ExpiresAt小于当前时间的记录。 - Login类冗余:Login仅作为请求参数载体,无需作为数据库实体,已从上下文移除,后续不要向
Logins集合添加数据。
内容的提问来源于stack exchange,提问作者gourav kumar
相关产品推荐
相关产品推荐

