从 TokenValidatedContext 获取签名

get signature from TokenValidatedContext

我正在为我的 .NET Core 项目使用 Microsoft.AspNetCore.Authentication.JwtBearerSystem.IdentityModel.Tokens.Jwt 包。

配置服务时,我正在向 OnTokenValidated 事件添加逻辑。

    services
        .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(jwtBearerOptions =>
        {
            // ... set TokenValidationParameters ...

            jwtBearerOptions.Events = new JwtBearerEvents()
            {
                OnTokenValidated = (tokenValidatedContext) => 
                {
                    JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
                    string tokenWithoutSignature = jwtSecurityTokenHandler.WriteToken(tokenValidatedContext.SecurityToken);

                    // ... full token from request? ...
                }
            };
        });

因为我只知道上下文 return 没有签名的令牌我想知道我怎么能


如果这不可能:

我正在以这种方式生成新令牌

public string GenerateAccessToken(IDictionary<string, object> payload)
{
    SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(Convert.FromBase64String("secret from config"));

    SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
    {
        Claims = payload,
        Expires = DateTime.Now, // value from config
        SigningCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256Signature)
    };

    JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
    SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
    string token = tokenHandler.WriteToken(securityToken);

    return token;
}

也许我可以找回

在这个方法中?


如果没有效果:

因为我知道不记名令牌总是包含三个部分,例如

header.payload.signature

我可以将字符串段拆分为一个数组,从数组中取出第一个和第二个元素并创建一个新字符串

firstString + . + secondString

那应该给我没有签名的令牌。是否有更好的想法从完整令牌中截断签名?


我为什么要实现这个?

本题基于此题

我正在使用访问和刷新令牌。在验证期间,我必须将请求中的令牌与数据库中的令牌进行比较。数据库中的令牌也包含签名。所以我面临着与上面链接相同的问题。

这就是为什么我想到了多种解决方案并将它们写在这里的原因。如果 TokenValidatedContext 无法 return 我的签名似乎我必须将 JWT 存储到没有签名的数据库中。同样对于这种情况,我需要将签名与生成的 JWT 分开。

没有 使用刷新令牌,我只将用户的最长会话生命周期存储到数据库中。流程是基于这个想法

Only store the time of the JWT with the highest lifetime to the database instead of the whole JWT

使用刷新令牌我想出了以下流程。 既然您知道 OnTokenValidated 处理验证逻辑,那么下面的逻辑是额外的。我有一个数据库 table

username | access_token | refresh_token | refresh_token_expires_at

主键是用户名+access_token的复合键。刷新令牌只是一些像这样生成的随机字符串

public string GenerateRefreshToken()
{
    var randomNumber = new byte[32];

    using (var rng = RandomNumberGenerator.Create())
    {
        rng.GetBytes(randomNumber);

        return Convert.ToBase64String(randomNumber);
    }
}

这就是我为其存储额外到期日期的原因。它应该可以在一段时间后过期。

为什么要操纵令牌?如果只是为了验证令牌,您可以使用下面的代码。

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)    
.AddJwtBearer(options =>    
{    
    options.TokenValidationParameters = new TokenValidationParameters    
    {    
        ValidateIssuer = true,    
        ValidateAudience = true,    
        ValidateLifetime = true,    
        ValidateIssuerSigningKey = true,    
        //ValidIssuer = Configuration["Issuer"],    
        //ValidAudience = Configuration["Audience"],    
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Key"]))    
    };    
});    

public void Configure(IApplicationBuilder app, IHostingEnvironment env)    
{    
    app.UseAuthentication();    
    app.UseMvc();    
} 

我不太明白你为什么要这样做,但如果你只需要原始令牌,你可以使用以下之一:

o.Events = new JwtBearerEvents
{
    OnTokenValidated = (context) =>
    {
        var securityToken = (System.IdentityModel.Tokens.Jwt.JwtSecurityToken)context.SecurityToken;
        var token = securityToken.RawData; // "ey...."
        var tokenHeader = securityToken.RawHeader; // "ey...."
        var tokenPayload = securityToken.RawPayload; // "ey...."
        var tokenSignatur = securityToken.RawSignature; // "ey...."
        var fullBearerHeader = context.Request.Headers["Authorization"]; // "Bearer ey..."
        return Task.CompletedTask;
    }
};

你可能想让代码在类型转换等方面更安全一些,但它应该给你令牌。