You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否使用.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 03:23:35