共计 3236 个字符,预计需要花费 9 分钟才能阅读完成。
背景与痛点
在现代 Web 应用中,身份验证是保障系统安全的核心机制。传统的 Session 方式虽然简单,但在分布式系统和微服务架构中暴露出明显不足:

- 服务器资源占用:Session 需要服务器存储用户状态,用户量增大时内存压力显著
- 扩展性差:集群环境下需要 Session 同步机制,增加复杂度
- 移动端适配:APP 等非浏览器客户端处理 Cookie 不够友好
- CSRF 风险:依赖 Cookie 的特性容易受到跨站请求伪造攻击
JWT(JSON Web Token)采用无状态验证机制,完美解决了这些问题。Token 包含所有必要信息,服务器只需验证签名无需存储状态,特别适合现代分布式架构。
JWT 核心概念
JWT 由三部分组成,通过点号连接:
Header.Payload.Signature
- Header:指定算法和类型(如 HS256)
- Payload:包含声明(用户 ID、角色等)和标准字段(exp 过期时间等)
- Signature:对前两部分签名,防止篡改
Token 的工作流程:
- 用户登录成功后服务器生成 JWT
- 客户端保存 Token 并在后续请求的 Header 中携带
- 服务端验证签名和声明后处理请求
实现步骤
1. 配置 JWT 服务
首先安装 NuGet 包:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
在 Program.cs 中配置服务:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
2. Token 生成与验证
创建 Token 生成服务:
public class TokenService
{
private readonly IConfiguration _configuration;
public TokenService(IConfiguration configuration)
{_configuration = configuration;}
public string GenerateToken(User user)
{var claims = new[]
{new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Role, user.Role)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(issuer: _configuration["Jwt:Issuer"],
audience: _configuration["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(30), // 短期有效
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
3. Token 刷新机制
实现双 Token 方案(AccessToken + RefreshToken):
// 登录接口返回两种 Token
var token = _tokenService.GenerateToken(user);
var refreshToken = _tokenService.GenerateRefreshToken();
// 存储 RefreshToken 到数据库
await _userService.SaveRefreshTokenAsync(user.Id, refreshToken);
return Ok(new { token, refreshToken});
// 刷新接口
[HttpPost("refresh")]
public async Task<IActionResult> Refresh(TokenModel tokenModel)
{var principal = _tokenService.GetPrincipalFromExpiredToken(tokenModel.AccessToken);
var userId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
// 验证 RefreshToken 有效性
var isValid = await _userService.ValidateRefreshTokenAsync(userId, tokenModel.RefreshToken);
if (!isValid) return Unauthorized();
// 生成新 Token
var newToken = _tokenService.GenerateToken(principal.Claims);
return Ok(new { token = newToken});
}
安全考量
防止 Token 盗用
- 始终使用 HTTPS 传输
- 设置合理的 Token 有效期(建议 AccessToken 15-30 分钟)
- 实现 Token 黑名单机制(用于主动注销)
- 避免在 URL 中传递 Token
敏感信息处理
- Payload 中不要存储密码等敏感信息
- 必要时对部分声明进行加密
- 使用强密钥(推荐至少 256 位)
性能优化
验证过程优化
- 启用缓存验证结果
- 对于高频接口可考虑短期跳过重复验证
- 使用高效的签名算法(HS256 比 RS256 更快)
大规模部署
- 考虑使用专门的认证服务
- 实现密钥轮换机制
- 监控 Token 验证性能指标
生产环境避坑指南
- 时钟偏移问题 :多服务器时间不同步会导致验证失败,设置
ClockSkew容忍偏差
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(5);
-
密钥泄露风险:不要硬编码密钥,使用 Key Vault 等安全存储
-
过度声明:Payload 不宜过大,影响网络性能
-
注销实现:JWT 本身无法废止,需要通过黑名单或短期有效期控制
-
算法混淆攻击:显式指定验证算法
options.TokenValidationParameters.ValidAlgorithms = new[] { "HS256"};
总结与扩展
本文实现的 JWT 验证方案已经可以满足大多数场景需求。如需更复杂的功能(如 OAuth2.0、OpenID Connect),可以考虑集成 IdentityServer4 等专业框架。
在微服务架构中,Token 通常需要在多个服务间传递验证。此时可以考虑:
- 使用 API 网关统一认证
- 实现 Token 转换(将外部 Token 转换为内部 Token)
- 采用共享密钥或集中式验证服务
思考题:在微服务架构中,如何实现跨服务的 Token 验证?
正文完
