我试图JWT
在ASP.NET Core Web API
项目中使用身份验证机制.假设此项目没有MVC
部分,并且不使用cookie身份验证.我已根据本指南创建了我的代码.
登录工作好,保护与[Authorize]
属性工作正常,但User.Identity.Name
就是null
.我怎样才能解决这个问题?
我的代码:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions)); var tokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)], ValidateAudience = true, ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)], ValidateIssuerSigningKey = true, IssuerSigningKey = _signingKey, RequireExpirationTime = true, ValidateLifetime = true, ClockSkew = TimeSpan.Zero }; app.UseJwtBearerAuthentication(new JwtBearerOptions { AutomaticAuthenticate = true, AutomaticChallenge = true, TokenValidationParameters = tokenValidationParameters, AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme }); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
[HttpPost] [AllowAnonymous] [Route("Login")] public async TaskLogin([FromForm] ApplicationUser applicationUser) { //assume user/pass are checked and are ok _logger.LogInformation(1, "API User logged in."); var user = await _userManager.FindByNameAsync(applicationUser.UserName); var roles = await _userManager.GetRolesAsync(user); var claims = new List { new Claim(JwtRegisteredClaimNames.Sub, applicationUser.UserName), new Claim(ClaimTypes.NameIdentifier, applicationUser.UserName), new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()), new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64), new Claim("Claim", "Value") }; if (roles != null) foreach (var role in roles) claims.Add(new Claim("role", role)); // Create the JWT security token and encode it. var jwt = new JwtSecurityToken( issuer: _jwtOptions.Issuer, audience: _jwtOptions.Audience, claims: claims, notBefore: _jwtOptions.NotBefore, expires: _jwtOptions.Expiration, signingCredentials: _jwtOptions.SigningCredentials); var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt); // Serialize and return the response var response = new { access_token = encodedJwt, expires_in = (int)_jwtOptions.ValidFor.TotalSeconds }; var json = JsonConvert.SerializeObject(response, _serializerSettings); return new OkObjectResult(json); }
jps.. 22
在您的声明(第二个代码段)中,我只能看到这个:
new Claim(ClaimTypes.NameIdentifier, applicationUser.UserName),
但你需要添加这个:
new Claim(ClaimTypes.Name, applicationUser.UserName),
那么User.Identity.Name应该包含用户名.
在您的声明(第二个代码段)中,我只能看到这个:
new Claim(ClaimTypes.NameIdentifier, applicationUser.UserName),
但你需要添加这个:
new Claim(ClaimTypes.Name, applicationUser.UserName),
那么User.Identity.Name应该包含用户名.
另一种选择是设置命名空间中JwtRegisteredClaimNames.Sub
的tokenValidationParameters
。这将使您继续使用该标准:
var tokenValidationParameters = new TokenValidationParameters { // Ensure that User.Identity.Name is set correctly after login NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", ... existing code ... }
更新:Diogo Barros在我的博客上就此主题发表了评论:
“你好,
谢谢您的帮助。这对我有用。为了获得更高的一致性和安全性,可以使用ClaimTypes.NameIdentifier(在System.Security.Claims命名空间中)代替硬编码的字符串。”
我已经更改了代码以使用内置的ClaimTypes枚举,因为它比使用命名空间字符串更优雅。