使用JWT令牌进行授权

7

我正在使用ASP.NET Core 5和ASP.NET Identity 3.0,并且同时使用Web页面和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();
  • 我该如何强制要求使用我的证书验证请求,以确保JWT令牌未被篡改。
  • 如果我没有使用JWT,但已经成功获得授权,那么应该设置哪些正确的参数来验证和授权我的JWT令牌。

请不要在问题标题中添加标签!http://stackoverflow.com/help/tagging - Tseng
2个回答

6
如果我禁用UseJsonWebTokens(),则可以生成令牌并成功授权。但是,我不确定我的证书是否验证了返回的令牌。
在ASOS(OpenIddict背后的OpenID Connect服务器框架)中,有两种不同的内置序列化机制来创建和保护令牌:
一种使用IdentityModel(由Microsoft开发的库)并生成第三方可验证的标准令牌:
身份验证令牌(根据定义为JWT)始终使用此过程创建,并且可以调用UseJsonWebTokens()来强制OpenIddict发出使用相同序列化过程的访问令牌。
调用AddSigningCertificate()时指定的证书始终用于签署这些令牌。
另一种使用ASP.NET Core数据保护堆栈(也由Microsoft开发):
该堆栈独占地生成“专有”令牌,不应由第三方阅读或验证,因为令牌格式不是标准的,并且必须依赖对称签名和加密。
当您使用默认令牌格式时,它是我们用于授权代码和刷新令牌的机制,这些令牌仅供OpenIddict本身消费。它也用于访问令牌。
在这种情况下,调用AddSigningCertificate()时指定的证书不会被使用。
相反,这些令牌始终由Data Protection堆栈使用身份验证加密算法(默认情况下为具有HMACSHA256的AES-256-CBC),提供真实性,完整性和机密性。为此,Data Protection堆栈从密钥环中存储的主密钥之一派生出2个密钥(一个用于加密,一个用于验证)。
如何强制请求与我的证书进行验证以确保JWT令牌未被篡改呢?哪些是正确的设置,将允许验证和授权我的JWT令牌,鉴于如果我不使用JWT,则会成功获得授权。
要回答这些问题,启用记录并共享跟踪信息将有所帮助。

1
这个默认的IdentityModel使用的签名密钥是什么?如果我想要使用一个Web Farm呢? - Adam
1
签名密钥是您使用的X.509证书(更准确地说是它包含的RSA密钥)。 - Kévin Chalet
1
密钥环是什么?我们如何在其中存储主密钥?这是否需要在启动期间调用 AddSigningKey() 函数? - Shaun Luttin
2
ASP.NET Core 数据保护文档应该是很有帮助的:https://docs.asp.net/en/latest/security/data-protection/index.html - Kévin Chalet

0

在ASP.NET Core中创建基于JWT Token的身份验证非常简单。请按照下面的链接,您将会得到更多的想法。 如何在Asp NET Core中创建JWT Token

示例代码

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 + "!";
    }


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接