无法使用ASP.NET Core从JWT令牌获取声明

19

我试图在ASP.NET Core中实现JWT承载身份验证的简单方法。我从控制器返回一个响应,就像这样:

    var identity = new ClaimsIdentity();
    identity.AddClaim(new Claim(ClaimTypes.Name, applicationUser.UserName));
        var jwt = new JwtSecurityToken(
             _jwtOptions.Issuer,
             _jwtOptions.Audience,
             identity.Claims,
             _jwtOptions.NotBefore,
             _jwtOptions.Expiration,
             _jwtOptions.SigningCredentials);

       var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

       return new JObject(
           new JProperty("access_token", encodedJwt),
           new JProperty("token_type", "bearer"),
           new JProperty("expires_in", (int)_jwtOptions.ValidFor.TotalSeconds),
           new JProperty(".issued", DateTimeOffset.UtcNow.ToString())
       );

我有用于处理传入请求的Jwt中间件:

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
     AutomaticAuthenticate = true,
     AutomaticChallenge = true,
     TokenValidationParameters = tokenValidationParameters
});

这似乎能够保护带有授权属性的资源,但是声明从未出现。

    [Authorize]
    public async Task<IActionResult> Get()
    {
        var user = ClaimsPrincipal.Current.Claims; // Nothing here

你尝试过使用 Context.User.Claims 吗? - Shaun Luttin
4个回答

20

在ASP.NET Core应用程序中,您不能使用ClaimsPrincipal.Current,因为它未由运行时设置。您可以阅读https://github.com/aspnet/Security/issues/322获取更多信息。

相反,考虑使用ControllerBase公开的User属性。


11

5
作为 ASP.NET Core 2.0 的一部分,您可以像 Shaun 上面描述的那样读取 JWT Claim。如果您只想查找用户 ID(请确保将其作为声明的一部分使用“Sub”声明名称添加),则可以根据您的用例使用以下两个示例之一进行读取:
读取用户 ID 声明:
    public class AccountController : Controller
    {
        [Authorize]
        [HttpGet]
        public async Task<IActionResult> MethodName()
        {
            var userId = _userManager.GetUserId(HttpContext.User);
            //...
            return Ok();
        }
    }

阅读其他声明:

    public class AccountController : Controller
    {
        [Authorize]
        [HttpGet]
        public async Task<IActionResult> MethodName()
        {
            var rolesClaim = HttpContext.User.Claims.Where( c => c.Type == ClaimsIdentity.DefaultRoleClaimType).FirstOrDefault();
            //...
            return Ok();
        }
    }

5
使用此解决方案,您可以在使用JWT令牌时,在控制器中访问User.Identity及其声明:
步骤1:创建一个JwtTokenMiddleware:
public static class JwtTokenMiddleware
{
    public static IApplicationBuilder UseJwtTokenMiddleware(
      this IApplicationBuilder app,
      string schema = "Bearer")
    {
        return app.Use((async (ctx, next) =>
        {
            IIdentity identity = ctx.User.Identity;
            if (identity != null && !identity.IsAuthenticated)
            {
                AuthenticateResult authenticateResult = await ctx.AuthenticateAsync(schema);
                if (authenticateResult.Succeeded && authenticateResult.Principal != null)
                    ctx.User = authenticateResult.Principal;
            }
            await next();
        }));
    }
}

步骤二:在Startup.cs中使用它。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseAuthentication();
    app.UseJwtTokenMiddleware();
}

虽然我不完全理解为什么,但这确实很有帮助。另外,你那令人难以置信的三元语句可以简化为 identity != null && !identity.IsAuthenticated - stuzor

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