第五章:JWT 认证与用户系统
博客v1.0系列教程(Csharp)博客 v1.0 系列教程 (C#)
5.1 JWT 配置
// appsettings.json
{
"JWT": {
"Secret": "your-256-bit-secret-key-here-must-be-long-enough",
"Issuer": "Blog",
"Audience": "Blog",
"ExpireMinutes": 1440
}
}
5.2 Token 服务
public class TokenService : ITokenService
{
private readonly IConfiguration _config;
public string GenerateToken(UserModel user)
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Role, user.Role.ToString()),
new Claim(ClaimTypes.Name, user.Username ?? "")
};
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.UtcNow.AddMinutes(expireMinutes),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public ClaimsPrincipal? ValidateToken(string token)
{
var handler = new JwtSecurityTokenHandler();
return handler.ValidateToken(token, GetValidationParameters(), out _);
}
}
5.3 登录接口
app.MapPost("/api/user/login", async (LoginDto dto, IUserService userService) =>
{
var user = await userService.GetByUsernameAsync(dto.Username);
if (user == null || !BCrypt.Net.BCrypt.Verify(dto.Password, user.Password))
return Results.Unauthorized();
var token = tokenService.GenerateToken(user);
return Results.Ok(new { Token = token, User = user });
});
5.4 Token 黑名单(Redis)
public class RedisTokenBlacklist
{
private readonly ConnectionMultiplexer _redis;
public async Task AddToBlacklistAsync(string token, TimeSpan expiry)
{
var db = _redis.GetDatabase();
await db.StringSetAsync($"blacklist:{token}", "true", expiry);
}
public async Task<bool> IsBlacklistedAsync(string token)
{
var db = _redis.GetDatabase();
return await db.KeyExistsAsync($"blacklist:{token}");
}
}
5.5 授权过滤器
public class AuthorizeFilter : IEndpointFilter
{
public async ValueTask<object?> InvokeAsync(
EndpointFilterInvocationContext context,
EndpointFilterDelegate next)
{
var token = context.HttpContext.Request.Headers["Authorization"]
.FirstOrDefault()?.Replace("Bearer ", "");
if (string.IsNullOrEmpty(token))
return Results.Unauthorized();
var principal = tokenService.ValidateToken(token);
if (principal == null)
return Results.Unauthorized();
context.HttpContext.User = principal;
return await next(context);
}
}
下一章将实现文章 CRUD 与 Markdown 支持。
csharpjwtauthsecurity