【问题标题】:Authorize via JWT Token通过 JWT Token 授权
【发布时间】:2016-11-27 06:17:25
【问题描述】:

带有 ASP.NET Identity 3.0 的 ASP.NET Core 5,我同时使用网页和 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,我将成功获得授权。

【问题讨论】:

标签: asp.net-core jwt openid-connect aspnet-contrib openiddict


【解决方案1】:

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

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

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

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

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

  • 使用 ASP.NET Core 数据保护堆栈的一种(也由 Microsoft 开发):

此堆栈专门生成“专​​有”令牌,不打算由第三方读取或验证,因为令牌格式不是标准的,并且必然依赖于对称签名和加密。

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

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

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

如何强制要求使用我的证书进行验证,以确保 JWT 令牌未被篡改。 什么是允许验证和授权我的 JWT 令牌的正确设置,如果我不使用 JWT,我将成功获得授权。

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

【讨论】:

  • 这个默认 IdentityModel 使用的签名密钥是什么?如果我想使用网络农场。
  • 签名密钥是您使用的 X.509 证书(更准确地说是它包含的 RSA 密钥)
  • 什么是钥匙圈?我们如何在其中存储主密钥?这是否需要在启动期间调用AddSigningKey()
  • ASP.NET Core 数据保护文档应该会有所帮助:docs.asp.net/en/latest/security/data-protection/index.html
【解决方案2】:

在 ASP.NET Core 中创建基于 JWT 令牌的身份验证非常简单。请点击以下链接,您将获得更多想法。 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 + "!";
    }


}

【讨论】:

    猜你喜欢
    • 2015-03-23
    • 2015-11-05
    • 2018-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-29
    • 2017-01-14
    • 2018-12-20
    相关资源
    最近更新 更多