共计 2406 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点:为什么需要 JWT?
在传统单体应用中,Session 认证是常见方案。但随着系统规模扩大,这种模式暴露出明显问题:

- 服务器内存压力 :每个用户会话都消耗服务器内存
- 横向扩展困难 :需要会话粘滞或共享存储
- CSRF 风险 :依赖 Cookie 容易被跨站伪造
- 移动端适配差 :原生 App 处理 Cookie 不够优雅
技术选型:JWT vs OAuth2
JWT 特别适合这些场景:
- 前后端分离架构
- 多服务间的无状态通信
- 需要携带轻量级用户信息的场景
对比 OAuth2/OIDC:
- OAuth2:适合第三方授权(如微信登录)
- OIDC:构建身份层,更复杂但功能完整
- 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,
ValidIssuer = "yourdomain.com",
ValidateAudience = true,
ValidAudience = "yourapp",
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(1), // 允许 1 分钟时钟偏移
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"]))
};
});
3. 登录接口实现
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly IConfiguration _config;
public AuthController(IConfiguration config)
{_config = config;}
[HttpPost("login")]
public IActionResult Login([FromBody] LoginModel model)
{
// 1. 实际项目这里应该验证数据库
if (model.Username != "admin" || model.Password != "123456")
return Unauthorized();
// 2. 生成 Token
var claims = new[]
{new Claim(JwtRegisteredClaimNames.Sub, model.Username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("CustomClaim", "SomeValue"), // 自定义 Claim
new Claim(ClaimTypes.Role, "Admin") // 角色声明
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Secret"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(30), // 短期有效
signingCredentials: creds);
return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
}
}
安全防护实战建议
密钥管理三原则
- 不要硬编码 :从配置或密钥管理系统获取
- 长度足够 :HS256 至少 32 字节随机字符串
- 定期轮换 :建立密钥版本机制
防范常见攻击
- CSRF:配合 SameSite Cookie 属性
- XSS:前端存储选用 HttpOnly Cookie
- 重放攻击 :使用 jti 声明和短期有效期
Token 存储方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 内存 | 简单快速 | 重启失效,不适合分布式 |
| Redis | 可扩展性强 | 需要额外基础设施 |
| 数据库 | 持久化可靠 | 性能最差 |
生产环境避坑指南
时钟偏移问题
多服务器时间不同步会导致 Token 验证失败,推荐方案:
// 设置合理的 ClockSkew
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(1);
性能优化
- 减少 Claim 数量(建议不超过 10 个)
- 对于频繁验证的场景缓存公钥
- 使用压缩算法处理大 Token
监控要点
- 记录异常的 Token 验证失败
- 监控 Token 生成频率异常
- 审计敏感 Claim 的修改
开放性问题:如何实现分布式登出?
JWT 的无状态特性使得传统的会话失效机制不再适用。可能的解决方案:
- 黑名单机制 :维护已注销 Token 的短名单
- 版本号控制 :用户登出时递增版本号
- 短期 Token+ 长期 RefreshToken:快速过期主动令牌
你更倾向于哪种方案?在实际项目中如何权衡实现复杂度与安全性?欢迎在评论区分享你的实践经验。
正文完
