在ASP.NET中,使用JWT(JSON Web Token)进行身份验证时,令牌撤销是一个重要的安全措施。以下是实现JWT令牌撤销的几种方法:
将JWT的过期时间设置得较短,例如几分钟或几小时。这样即使Token被泄露,攻击者也只能在有限的时间内使用它。
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes("your_secret_key");
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, "John Doe"),
new Claim(ClaimTypes.Email, "john.doe@example.com")
}),
Expires = DateTime.UtcNow.AddMinutes(30),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
引入一个刷新Token的概念,用于在访问Token过期后获取新的访问Token。刷新Token应该存储在安全的地方,例如HttpOnly Cookie。
var refreshTokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes("your_refresh_secret_key");
var refreshTokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, "John Doe"),
new Claim(ClaimTypes.Email, "john.doe@example.com")
}),
Expires = DateTime.UtcNow.AddDays(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var refreshToken = refreshTokenHandler.CreateToken(refreshTokenDescriptor);
var refreshTokenString = refreshTokenHandler.WriteToken(refreshToken);
维护一个黑名单,存储所有需要撤销的Token。每次验证Token时,首先检查该Token是否在黑名单中。
public class JwtTokenRevocationService
{
private readonly IList<string> _revokedTokens = new List<string>();
public void RevokeToken(string token)
{
_revokedTokens.Add(token);
}
public bool IsTokenRevoked(string token)
{
return _revokedTokens.Contains(token);
}
}
在验证Token时,使用JwtTokenRevocationService
检查Token是否被撤销:
public class JwtTokenValidator
{
private readonly JwtTokenRevocationService _revocationService;
public JwtTokenValidator(JwtTokenRevocationService revocationService)
{
_revocationService = revocationService;
}
public bool ValidateToken(string token)
{
if (_revocationService.IsTokenRevoked(token))
{
return false;
}
// 其他验证逻辑
var tokenHandler = new JwtSecurityTokenHandler();
try
{
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_secret_key")),
ValidateIssuer = false,
ValidateAudience = false
};
var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
return principal != null;
}
catch (Exception ex)
{
// 处理异常
return false;
}
}
}
将需要撤销的Token存储在数据库或缓存中,以便快速查找和验证。
public class JwtTokenRevocationService
{
private readonly IDatabaseContext _databaseContext;
public JwtTokenRevocationService(IDatabaseContext databaseContext)
{
_databaseContext = databaseContext;
}
public void RevokeToken(string token)
{
_databaseContext.RevokedTokens.Add(new RevokedToken { Token = token, Expiry = DateTime.UtcNow });
_databaseContext.SaveChanges();
}
public bool IsTokenRevoked(string token)
{
return _databaseContext.RevokedTokens.Any(rt => rt.Token == token);
}
}
以上方法各有优缺点,选择哪种方法取决于具体的应用场景和安全需求。短期Token、刷新Token和黑名单机制是比较常见的解决方案,而使用数据库或缓存则可以提供更高级别的安全性。