首页 > 解决方案 > 来自 OnTokenValidated 事件侦听器的 TokenValidatedContext 的安全令牌缺少最后一个字符串段

问题描述

我将Microsoft.AspNetCore.Authentication.JwtBearerSystem.IdentityModel.Tokens.Jwt用于我的 .NET Core 项目。

每当我生成一个新令牌时,我都会将其存储到数据库中。首先这是我生成新令牌的方式

    public string GenerateToken(Dictionary<string, object> payload)
    {
        DateTime tokenExpiresAt = DateTime.Now.AddMilliseconds(1); // from config
        byte[] symmetricKey = Convert.FromBase64String("secret"); // from config
        SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(symmetricKey);
    
        SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
        {
            Claims = payload,
            Expires = tokenExpiresAt,
            SigningCredentials = new SigningCredentials(symmetricSecurityKey, 
                SecurityAlgorithms.HmacSha256Signature)
        };
    
        JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
        SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
        string token = tokenHandler.WriteToken(securityToken);

        return token;
    }

生成的样本令牌是

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwibmJmIjoxNTk1NDQ1NjMxLCJleHAiOjE1OTU0NDU2OTEsImlhdCI6MTU5NTQ0NTYzMX0.cWvSpKC_yYao2I_ziW_vxjxx

如果客户端尝试访问受保护的端点,默认配置将处理基本验证(在启动文件的 DI 设置中配置)

        services
            .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(jwtBearerOptions =>
            {
                byte[] symmetricKey = Convert.FromBase64String("secret"); // from config
                SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(symmetricKey);
                
                jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidateIssuerSigningKey = true,
                    ValidateLifetime = true,
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    IssuerSigningKey = symmetricSecurityKey,
                };

                jwtBearerOptions.Events = new JwtBearerEvents()
                {
                    OnTokenValidated = ProcessAfterTokenValidation
                };
            });

如您所见,我向OnTokenValidated事件侦听器添加了一个方法。此方法应检查令牌是否存在于数据库中。

    public async Task ProcessAfterTokenValidation(TokenValidatedContext tokenValidatedContext)
    {
        JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
        string token = jwtSecurityTokenHandler.WriteToken(tokenValidatedContext.SecurityToken);
        
        // ... check if token exists in db ...
    }

该方法的问题在于生成的令牌不是存储在数据库中的确切令牌。缺少最后一段。token 变量保存了这个

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwibmJmIjoxNTk1NDQ1NjMxLCJleHAiOjE1OTU0NDU2OTEsImlhdCI6MTU5NTQ0NTYzMX0。

缺少的最后一部分是

cWvSpKC_yYao2_ziW_ahjjHpUl2SgUZvCmsjXntxCOI

有人知道为什么令牌的最后一部分丢失了吗?

感谢帮助!

标签: c#.net-coreasp.net-core-webapiadal

解决方案


令牌的最后一部分是签名。OnTokenValidated方法的目的是提供 ClaimsIdentity。签名不是令牌持有者声明的组成部分。

如果您在发行方有密钥轮换策略,则给定用户可以在密钥轮换之前和之后提出具有不同签名的相同声明。

用户的身份来自发行者加上任何标识用户的声明的组合(例如username,在您的示例中的令牌中)。

在您的情况下,由于您是发行者,因此减去签名的令牌仅表示用户已成功通过您的令牌发行端点进行身份验证的证明。令牌中的声明应该指向数据库记录,而不是令牌本身。


推荐阅读