通过 JWT Token 授权

Authorize via JWT Token

ASP.NET Core 5 with ASP.NET Identity 3.0,我同时使用网页和 api。我正在使用 OpenIddict 颁发 JWT 令牌并进行身份验证。我的代码看起来是这样的:

    X509Certificate2 c = new X509Certificate2(@"tokensign.p12", "MyCertificatePassword");

    services.AddOpenIddict<WebUser, IdentityRole<int>, WebDbContext, int>()
        .EnableTokenEndpoint("/api/customauth/login")
        .AllowPasswordFlow()
        .UseJsonWebTokens()
        .AddSigningCertificate(c);

如果我禁用 UseJsonWebTokens(),我可以生成令牌并成功授权。但是,我不确定我的证书是否正在验证返回的令牌。

当启用 UseJsonWebTokens 时,我可以在此端点发出 JWT 令牌。但是,我无法验证任何请求!

我在应用程序配置中使用以下代码:

    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        RequireHttpsMetadata = false,
        Authority = "http://localhost:60000/",
        Audience = "http://localhost:60000/",
    });
    app.UseOAuthValidation();
    app.UseIdentity();
    app.UseOpenIddict();
    app.UseMvcWithDefaultRoute();

If I disable UseJsonWebTokens(), I can generate a token and authorise successfully. However, I am not sure that my certificate is validating the returned tokens.

在 ASOS(OpenIddict 背后的 OpenID Connect 服务器框架)中,有 2 种不同的内置序列化机制来创建和保护令牌:

  • 一个使用 IdentityModel(Microsoft 开发的库)并生成可由第三方验证的标准令牌:

身份令牌(定义为 JWT)始终使用此过程创建,您可以调用 UseJsonWebTokens() 强制 OpenIddict 颁发使用相同序列化过程的访问令牌。

您在调用 AddSigningCertificate() 时指定的证书始终用于签署这些令牌。

  • 一个使用 ASP.NET 核心数据保护堆栈(也由 Microsoft 开发):

此堆栈专门生成 "proprietary" 令牌,不打算由第三方读取或验证,因为令牌格式不标准且必须依赖关于对称签名和加密。

这是我们用于授权代码和刷新令牌的机制,仅供 OpenIddict 本身使用。当您使用默认令牌格式时,它也用于访问令牌。

在这种情况下,调用AddSigningCertificate()时指定的证书不会被使用。

相反,这些令牌始终由数据保护堆栈使用 Authenticated Encryption 算法(默认情况下,AES-256-CBC 和 HMACSHA256)加密,提供真实性、完整性和机密性。为此,数据保护堆栈从存储在密钥环中的主密钥之一派生出 2 个密钥(一个用于加密,一个用于验证)。

How can I enforce the request to be validated with my certificate to make sure the JWT token is not tampered with. What are the correct settings that will allow validation and authorisation of my JWT token, given that if I am not using JWT, I am getting authorised successfully.

要回答这些问题,如果您启用了日志记录并分享了您的踪迹,将会有所帮助。

在 ASP.NET Core 中创建基于 JWT 令牌的身份验证非常非常简单。请按照下面link你会得到更多的想法。 How to Create JWT Token in Asp NET Core

示例代码

public static class AuthenticationConfig
{
    public static string GenerateJSONWebToken(string user)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("730F046B1ADF1555FF0C80149B47B38CD7C0A146AAFA34870E863CAA25B585C3"));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[] {
             new Claim("UserName", user),
              new Claim("Role", "1"),
                };

        var token = new JwtSecurityToken("http://localhost:30972",
          "http://localhost:30972",
          claims,
          DateTime.UtcNow,
          expires: DateTime.Now.AddMinutes(10),
          signingCredentials: credentials);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

    //ConfigureJwtAuthentication
    internal static TokenValidationParameters tokenValidationParams;
    public static void ConfigureJwtAuthentication(this IServiceCollection services)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("730F046B1ADF1555FF0C80149B47B38CD7C0A146AAFA34870E863CAA25B585C3"));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        tokenValidationParams = new TokenValidationParameters()
        {
            ValidateIssuerSigningKey = true,
            ValidIssuer = "http://localhost:30972",
            ValidateLifetime = true,
            ValidAudience = "http://localhost:30972",
            ValidateAudience = true,
            RequireSignedTokens = true,
            // Use our signing credentials key here
            // optionally we can inject an RSA key as
            //IssuerSigningKey = new RsaSecurityKey(rsaParams),
            IssuerSigningKey = credentials.Key,
            ClockSkew = TimeSpan.FromMinutes(10)
        };
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })

        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = tokenValidationParams;
            #if PROD || UAT
                  options.IncludeErrorDetails = false;
            #elif DEBUG
                  options.RequireHttpsMetadata = false;
            #endif
        });
    }
}

在Startup.cs

中添加这一行
 public void ConfigureServices(IServiceCollection services)
    {
        services.ConfigureJwtAuthentication();
        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new  AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
        });
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

在身份验证控制器中添加这些行

[Route("api/[controller]")]
public class AuthenticationController : Controller
{
    // GET: api/<controller>
    [HttpGet]
    public string Get(string user, string pass)
    {
        if (user == "admin")
        {
            return AuthenticationConfig.GenerateJSONWebToken(user);
        }
        else
        {
            return "";
        }

    }


    // POST api/<controller>
    [Authorize]
    [HttpPost]
    public string Post()
    {
        var identity = HttpContext.User.Identity as ClaimsIdentity;
        IEnumerable<Claim> claim = identity.Claims;
        var UserName = claim.Where(c => c.Type == "UserName").Select(c => c.Value).SingleOrDefault();

        return "Welcome to " + UserName + "!";
    }


}