如何验证从一个应用程序在另一个应用程序中生成的 JWT 令牌?

Sat*_*hya 10 c# authentication jwt asp.net-core

首先,感谢您花时间阅读本文。

我需要验证由一个 .net core 2.2 应用程序在另一个 .net core 3.1 应用程序中生成的 JWT 令牌。

目前,我无法使用 .net 核心授权来验证令牌,但能够编写单独的方法来验证令牌。我确保用于签署令牌的秘密是相同的。

如何使用 .net core 3.1 中的内置身份验证来验证从不同应用程序生成的令牌。

以下是详细说明:

我创建了一个用于登录请求的 API,它使用本教程生成 JWT 令牌以在 .net core 2.2 上进行验证。

在我的登录 API 中,在 startup.cs 中,我添加了如下身份验证:

        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);
        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        });
Run Code Online (Sandbox Code Playgroud)

我生成这样的令牌:

        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.Name, dbUser.UserID.ToString())
            }),
            Expires = DateTime.Now.AddMinutes(_appSettings.Expiry_Min),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
            Audience = _appSettings.Audience,
            Issuer = _appSettings.Issuer,
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
Run Code Online (Sandbox Code Playgroud)

JWT 令牌效果很好。在我的控制器中,我添加了 [Authorize] 属性,带有无效令牌的请求会被立即拒绝。

现在,我想在 .net core 3.1 中的另一个应用程序中验证我的登录 API 生成的令牌,以验证登录响应。为此,我参考了本教程。在第二个应用程序的 startup.cs 中,我有:

    private void SetupJWTServices(IServiceCollection services)
    {
        // configure strongly typed settings objects
        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);

        // configure jwt authentication
        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);

        services.AddAuthentication(x =>
        {
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(x =>
        {
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            };
        });
Run Code Online (Sandbox Code Playgroud)

该方法的调用方式如下:

    public void ConfigureServices(IServiceCollection services)
    {
        SetupJWTServices(services);            
        services.AddControllers();

        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);
    }
Run Code Online (Sandbox Code Playgroud)

在我的第二个应用程序中,当我使用 [Authorize] 属性时,请求立即被 401 拒绝,未经授权。但是,当我不使用 [Authorize] 属性并创建一个方法来验证令牌时,该方法能够验证所有有效请求。我写的方法是:

    private void Validator(string token)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var appSettingsSection = _appConfiguration.GetSection("AppSettings");
        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);
        try
        {
            tokenHandler.ValidateToken(token, new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
                ClockSkew = TimeSpan.Zero
            }, out SecurityToken validatedToken);

            var jwtToken = (JwtSecurityToken)validatedToken;

            // return account id from JWT token if validation successful
        }
        catch
        {
            // return null if validation fails
        }
Run Code Online (Sandbox Code Playgroud)

这对我来说意味着要验证所有请求,我需要在处理任何内容之前首先通过此验证器方法传递它。但是,这并没有使用内置的授权控制。好像不对。

这就是在不同应用程序之间验证 JWT 令牌的方式吗?

小智 1

使用声明来验证令牌

static public bool ValidacionTokenManual(string Token, string secretKey, string audienceToken, string issuerToken)
    {
        TokenValidationParameters validationParameters = new TokenValidationParameters()
        {
            ValidAudience = audienceToken,
            ValidIssuer = issuerToken,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(secretKey))
        };

        SecurityToken validateToken;
        JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();

        if(handler.CanReadToken(Token))
        {
            var user = handler.ValidateToken(Token, validationParameters, out validateToken);

            string roles = user.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role)?.Value;
            if(roles != "")
            {
                return true;
            }
        }

        return false;
    }
Run Code Online (Sandbox Code Playgroud)