共计 2722 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点
在传统的单体应用架构中,Session 认证是常见的用户认证方式。但随着微服务架构的流行,Session 的局限性逐渐暴露:

- 服务器内存开销大,每个用户会话都需要存储
- 难以跨服务共享,需要依赖粘性会话或中央存储
- 扩展性差,新增服务器节点时需要同步 Session
- CSRF 防护依赖额外机制(如 Anti-Forgery Token)
技术选型
JWT 与 OAuth2/OIDC 都是现代认证方案,但适用场景不同:
- JWT:
- 自包含令牌,适合服务间信任的简单场景
- 无状态,服务端不需要存储会话信息
-
轻量级,适合移动端和前后端分离架构
-
OAuth2/OIDC:
- 适合第三方授权场景(如使用 Google/Facebook 登录)
- 需要授权服务器参与,流程更复杂
- 支持更细粒度的权限控制
对于大多数内部系统,JWT 提供了足够的安全性和简便性。
核心实现
1. 安装必要 NuGet 包
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt
2. Startup 配置
// 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"]))
};
});
3. Token 生成服务
public class TokenService
{
private readonly IConfiguration _configuration;
public TokenService(IConfiguration configuration)
{_configuration = configuration;}
public string GenerateToken(User user)
{var claims = new[]
{new Claim(JwtRegisteredClaimNames.Sub, user.Id),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
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 expires = DateTime.Now.AddMinutes(Convert.ToDouble(_configuration["Jwt:ExpireMinutes"]));
var token = new JwtSecurityToken(issuer: _configuration["Jwt:Issuer"],
audience: _configuration["Jwt:Audience"],
claims: claims,
expires: expires,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
4. 登录控制器
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly TokenService _tokenService;
public AuthController(TokenService tokenService)
{_tokenService = tokenService;}
[HttpPost("login")]
public IActionResult Login([FromBody] LoginRequest request)
{
// 1. 验证用户凭证(省略具体实现)var user = AuthenticateUser(request.Username, request.Password);
if (user == null)
return Unauthorized();
// 2. 生成 Token
var token = _tokenService.GenerateToken(user);
// 3. 返回 Token 和刷新 Token
return Ok(new
{
token,
refreshToken = GenerateRefreshToken(user.Id)
});
}
}
安全考量
1. 密钥管理
- 生产环境不要硬编码密钥
- 使用密钥管理系统(如 Azure Key Vault)
- 定期轮换密钥
2. Token 存储
| 方案 | 优点 | 缺点 |
|---|---|---|
| 客户端存储 | 无服务器开销 | 有 XSS 风险 |
| HttpOnly Cookie | 防 XSS | 需处理 CSRF |
| Redis 集中存储 | 可主动失效 | 引入依赖 |
3. 敏感信息处理
- 不要在 JWT 中存储密码等敏感信息
- 必要时加密 Payload
- 使用短期有效的 Token
避坑指南
- 时钟偏移问题:
- 服务器间时间不同步会导致 Token 验证失败
-
设置
ClockSkew容忍小范围偏差 -
性能优化:
- 减少 Claims 数量
-
考虑使用引用 Token+ 数据库查询的方案
-
日志监控:
- 记录异常的 Token 验证
- 监控 Token 生成频率
开放问题
在分布式系统中,如何实现 JWT 的主动失效?常见方案包括:
- 维护 Token 黑名单
- 使用短期 Token+ 长期 RefreshToken
- 在网关层统一校验
每种方案各有什么优缺点?欢迎在评论区分享你的见解。
正文完
