【问题标题】:Get claims from JWT token in ASP.NET Core 2.0 API从 ASP.NET Core 2.0 API 中的 JWT 令牌获取声明
【发布时间】:2018-06-16 11:50:27
【问题描述】:

我在我的 ASP.NET Core 2.0 Web 和 API 应用程序中使用混合身份验证。意思是 cookie,现在添加 JWT token

应用程序的 Web 部分使用 cookie,而在 API 部分,我想使用 JWT 令牌。

我的问题是如何从JWT token 获得索赔?在我的网络控制器中,我可以简单地使用 HttpContext.User; 来获取存储在 cookie 中的声明。如何在我想要使用JWT token 的 API 方法中处理它?

这是我的 AuthenticationBuilder:

public static void MyAuthenticationConfig(IServiceCollection services, IConfiguration configuration)
{
   services.AddAuthentication(options =>
   {
      options.DefaultAuthenticateScheme = "myApp_cookie";
      options.DefaultChallengeScheme = "myApp_cookie";
    })
    .AddCookie("myApp_cookie", options =>
    {
      options.AccessDeniedPath = "/Unauthorized";
      options.LoginPath = "/Login";
    })
    .AddCookie("social_auth_cookie")
    .AddOAuth("LinkedIn", options =>
    {
      options.SignInScheme = "social_auth_cookie";

      options.ClientId = "my_client_id";
      options.ClientSecret = "my_secret";

      options.CallbackPath = "/linkedin-callback";

      options.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization";
      options.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken";
      options.UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,picture-url,picture-urls::(original))";

      options.Scope.Add("r_basicprofile");
      options.Scope.Add("r_emailaddress");

      options.Events = new OAuthEvents
      {
         OnCreatingTicket = OnCreatingTicketLinkedInCallBack,
         OnTicketReceived = OnTicketReceivedCallback
       };
    })
    .AddFacebook(options =>
    {
        options.SignInScheme = "social_auth_cookie";
        options.AppId = "my_app_is";
        options.AppSecret = "my_secret";
        options.Events = new OAuthEvents
        {
           OnCreatingTicket = OnCreatingTicketFacebookCallback,
           OnTicketReceived = OnTicketReceivedCallback
         };
     })
     .AddGoogle(options =>
     {
         options.SignInScheme = "social_auth_cookie";
         options.ClientId = "my_id.apps.googleusercontent.com";
         options.ClientSecret = "my_secret";
         options.CallbackPath = "/google-callback";
         options.Events = new OAuthEvents
         {
             OnCreatingTicket = OnCreatingTicketGoogleCallback,
             OnTicketReceived = OnTicketReceivedCallback
         };
      })
      .AddJwtBearer("JwtBearer", jwtBearerOptions =>
      {
         jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
         {
             ValidateIssuerSigningKey = true,
             IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("my_secret")),

             ValidateIssuer = true,
             ValidIssuer = "my-api",

             ValidateAudience = true,
             ValidAudience = "my-client",

             ValidateLifetime = true,

             ClockSkew = TimeSpan.FromMinutes(5)
        };
    });
}

【问题讨论】:

    标签: asp.net asp.net-web-api asp.net-core jwt asp.net-core-2.0


    【解决方案1】:

    JWT 的声明通常会自动添加到 ClaimsIdentity。

    来源:
    https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/af5e5c2b0100e8348c63e2d2bb45612e2080841e/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs#L1110)。

    所以您应该能够只使用基“控制器”类的“用户”属性。

    public async Task<IActionResult> Get()
    {
        // TODO Move 'Claims' extraction code to an extension method
        var address = User.Claims.Where('GET THE NEEDED CLAIM');
        ...
    }
    

    我从 JWT 令牌中获取声明从未遇到任何问题。 但到目前为止,我只使用了 IdentityServer4.AccessTokenValidation。但在内部它使用 Microsoft JWT Handler afaik。

    【讨论】:

    • 我可以在 HttpContext.User.Identity 上使用 IsInRole 吗?
    【解决方案2】:

    无法发表评论,因为我的帖子太长了,所以单独发一个帖子。

    如果您按照 ErazerBrecht 发布的指南/链接进行操作,则声明确实存储在 ClaimsPrincipal 用户中。我创建了一个扩展方法来检索声明。

    请注意,我使用 Enum 来注册我的声明。我使用字典将我的声明传递给生成我的令牌的方法,因此我的声明键应该始终是唯一的。

    扩展方法:

    public static string GetClaim(this ClaimsPrincipal claimsPrincipal, JwtClaim jwtClaim)
    {
      var claim = claimsPrincipal.Claims.Where(c => c.Type == jwtClaim.ToString()).FirstOrDefault();
    
      if (claim == null)
      {
          throw new JwtClaimNotFoundException(jwtClaim);
      }
    
      return claim.Value;
    }
    

    这样称呼:

    var userId = User.GetClaim(JwtClaim.UserId);
    

    【讨论】:

    • FirstOrDefault().Value 如果未找到声明将引发异常。我建议将 .Value 移到您的 return 语句中。 (返回索赔。价值)。然后,您正在检查声明是否为空,而不是声明的值为空。
    • 你说得对,我今天测试代码的时候发现了这个!随着另一个错误。 nameof() 应该被 ToString() 替换,因为我们想要的是变量的值,而不是名称!我将编辑帖子以反映这一点。我想我应该马上写单元测试!
    猜你喜欢
    • 2018-07-01
    • 2023-03-23
    • 2019-08-03
    • 2020-01-17
    • 2018-03-30
    • 2019-10-26
    • 1970-01-01
    • 2021-04-21
    • 2019-01-21
    相关资源
    最近更新 更多