能否使用.NET 8 Bearer Token认证处理器生成引用令牌而非自包含JWT?
问题
我当前使用IdentityServer4 v3.1.1搭配引用令牌,但因新许可政策及功能冗余等原因,希望完全弃用IdentityServer。不过我偏好引用令牌而非JWT风格令牌,原因有二:
- a) 不包含实际数据;
- b) 支持吊销,这对我们的应用至关重要。
同时我也青睐.NET 8新Bearer Token认证处理器的简洁性。是否有办法在使用.NET 8新认证组件的同时继续使用引用令牌?
解决方案
是的,你可以在.NET 8的新Bearer Token认证组件中继续使用引用令牌,核心是通过自定义令牌验证逻辑替代IdentityServer的引用令牌处理流程。以下是具体实现步骤:
1. 基础配置:启用Bearer认证
在Program.cs中添加基础Bearer认证配置,后续扩展其验证逻辑:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 禁用默认JWT验证逻辑,交由自定义处理器处理 options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = false, ValidateIssuerSigningKey = false }; // 替换默认验证器为自定义引用令牌验证器 options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Add(new ReferenceTokenValidator()); });
2. 实现自定义引用令牌验证器
创建实现ISecurityTokenValidator的类,负责验证引用令牌的有效性、吊销状态等:
public class ReferenceTokenValidator : ISecurityTokenValidator { private readonly ITokenStore _tokenStore; public ReferenceTokenValidator(ITokenStore tokenStore) { _tokenStore = tokenStore; } public bool CanValidateToken => true; public int MaximumTokenSizeInBytes => int.MaxValue; public bool CanReadToken(string securityToken) { // 根据你的引用令牌格式判断(示例:32位随机字符串) return !string.IsNullOrEmpty(securityToken) && securityToken.Length == 32; } public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) { validatedToken = null; // 1. 查询令牌基础信息 var tokenInfo = _tokenStore.GetTokenInfo(securityToken); if (tokenInfo == null) { throw new SecurityTokenInvalidException("无效的引用令牌"); } // 2. 检查是否已吊销 if (tokenInfo.IsRevoked) { throw new SecurityTokenRevokedException("引用令牌已被吊销"); } // 3. 检查是否过期 if (tokenInfo.ExpirationTime < DateTime.UtcNow) { throw new SecurityTokenExpiredException("引用令牌已过期"); } // 4. 构建用户身份凭证 var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, tokenInfo.UserId), new Claim(ClaimTypes.Name, tokenInfo.Username), // 添加业务所需的其他Claim }; var identity = new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme); return new ClaimsPrincipal(identity); } }
3. 实现令牌存储与吊销服务
创建令牌存储接口及实现,负责管理令牌的创建、查询、吊销逻辑:
public interface ITokenStore { TokenInfo GetTokenInfo(string token); void RevokeToken(string token); string CreateToken(string userId, string username, TimeSpan expiration); } public class TokenInfo { public string Token { get; set; } public string UserId { get; set; } public string Username { get; set; } public DateTime ExpirationTime { get; set; } public bool IsRevoked { get; set; } } // 生产环境建议替换为Redis/数据库存储,以下为内存存储示例 public class InMemoryTokenStore : ITokenStore { private readonly Dictionary<string, TokenInfo> _tokens = new(); private readonly object _lock = new(); public TokenInfo GetTokenInfo(string token) { lock (_lock) { _tokens.TryGetValue(token, out var info); return info; } } public void RevokeToken(string token) { lock (_lock) { if (_tokens.TryGetValue(token, out var info)) { info.IsRevoked = true; } } } public string CreateToken(string userId, string username, TimeSpan expiration) { var token = Guid.NewGuid().ToString("N"); lock (_lock) { _tokens[token] = new TokenInfo { Token = token, UserId = userId, Username = username, ExpirationTime = DateTime.UtcNow.Add(expiration), IsRevoked = false }; } return token; } }
4. 注册自定义服务
在Program.cs中注册令牌存储和自定义验证器:
builder.Services.AddSingleton<ITokenStore, InMemoryTokenStore>(); builder.Services.AddSingleton<ISecurityTokenValidator, ReferenceTokenValidator>();
5. 令牌颁发与吊销接口
替换IdentityServer的授权流程,实现自己的登录、吊销接口:
[ApiController] [Route("auth")] public class AuthController : ControllerBase { private readonly ITokenStore _tokenStore; public AuthController(ITokenStore tokenStore) { _tokenStore = tokenStore; } [HttpPost("login")] public IActionResult Login([FromBody] LoginRequest request) { // 替换为实际用户身份验证逻辑 if (request.Username == "test" && request.Password == "password") { var token = _tokenStore.CreateToken("user123", request.Username, TimeSpan.FromHours(1)); return Ok(new { AccessToken = token, TokenType = "Bearer" }); } return Unauthorized(); } [HttpPost("revoke")] [Authorize] public IActionResult Revoke([FromBody] RevokeRequest request) { _tokenStore.RevokeToken(request.Token); return Ok(); } } public class LoginRequest { public string Username { get; set; } public string Password { get; set; } } public class RevokeRequest { public string Token { get; set; } }
关键注意事项
- 生产环境存储:不要使用内存存储,建议用Redis(支持自动过期清理)或关系型数据库,保证数据持久化和性能。
- 安全加固:引用令牌需通过HTTPS传输;可给令牌添加HMAC签名,验证时先校验签名防止篡改。
- 性能优化:给令牌验证逻辑添加缓存,减少存储查询次数。
内容的提问来源于stack exchange,提问作者Chris Gilbert
相关产品推荐
相关产品推荐

