![](/img/trans.png)
[英]ASP.NET Core 5.0 JWT authentication is always throws HTTP 401 code
[英]ASP.NET Core 5 JWT Authentication fails with response code 401
我正在嘗試在我的 ASP.NET Core 5 Web API 中實現基於 JWT 的身份驗證。 但是,在使用標有[Authorize]
屬性的 API 時,我總是以響應代碼 401 結束。
這是我到目前為止所擁有的。 首先,如果用戶提供有效的用戶名和密碼,我的AccountController
發出 JWT:
[Authorize]
[ApiController]
[Route("api/" + Constants.ApiVersion + "/Accounts")]
public class AccountController : ControllerBase
{
private readonly UserManager<AppUser> _userManager;
private readonly IPasswordHasher<AppUser> _passwordHasher;
public AccountController(UserManager<AppUser> userManager, IPasswordHasher<AppUser> passwordHasher)
{
_userManager = userManager;
_passwordHasher = passwordHasher;
}
[AllowAnonymous]
[HttpPost]
[Route("Token")]
public async Task<IActionResult> Login([FromForm]LoginBindingModel model)
{
if(model == null)
{
return BadRequest();
}
if(!ModelState.IsValid)
{
return BadRequest(ModelState);
}
AppUser user = await _userManager.FindByNameAsync(model.UserName);
if(user == null || !await _userManager.CheckPasswordAsync(user, model.Password))
{
return Unauthorized();
}
SymmetricSecurityKey encryptionKey = new(Encoding.UTF8.GetBytes("TODO_Find_better_key_and_store_as_secret"));
JwtSecurityTokenHandler jwtTokenHandler = new();
SecurityTokenDescriptor tokenDescriptor = new()
{
Subject = new ClaimsIdentity(new[] { new Claim("UserName", user.UserName) }),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(encryptionKey, SecurityAlgorithms.HmacSha256Signature)
};
SecurityToken jwtToken = jwtTokenHandler.CreateToken(tokenDescriptor);
string token = jwtTokenHandler.WriteToken(jwtToken);
return Ok(token);
}
[HttpPost]
[Route("ChangePassword")]
public async Task<ActionResult> ChangePassword([FromBody]ChangePasswordBindingModel model)
{
if(model == null)
{
return BadRequest();
}
if(!ModelState.IsValid)
{
return BadRequest(ModelState);
}
AppUser user = await _userManager.GetUserAsync(User);
if(user == null)
{
return new StatusCodeResult(StatusCodes.Status403Forbidden);
}
IdentityResult result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
return GetHttpResponse(result);
}
...
}
這段代碼似乎可以正常工作。 它返回一個由jwt.io成功解析並包含我放入其中的用戶名的令牌。
接下來,Startup 類如下所示:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration
{
get;
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApplicationSettings>(Configuration.GetSection(nameof(ApplicationSettings)));
services.AddIdentityCore<AppUser>(options =>
{
Configuration.GetSection(nameof(IdentityOptions)).Bind(options);
});
services.AddScoped<IPasswordHasher<AppUser>, Identity.PasswordHasher<AppUser>>();
services.AddTransient<IUserStore<AppUser>, UserStore>();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "whatever",
ValidateAudience = true,
ValidAudience = "whatever",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("TODO_Find_better_key_and_store_as_secret"))
};
});
services.AddMvc();
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
我正在向Token
路由發送一個 HTTP POST 請求,該請求返回 JWT。 之后,我將一個 HTTP POST 請求在請求正文中包含必要的 JSON 數據和Authorization: Bearer <the JWT>
發送到ChangePassword
路由。
但是,它總是返回響應代碼 401,沒有任何附加信息或異常。
我不知道Startup.ConfigureServices
的魔法實際上應該在幕后做什么。 無論如何,這顯然行不通。 有誰知道發生了什么以及如何使其工作?
但是,它總是返回響應代碼 401,沒有任何附加信息或異常。
這是因為您將ValidateIssuer
和ValidateAudience
設置為 true 但生成的令牌中沒有Issuer
和Audience
。
一種方法是您可以在代碼中設置Issuer
和Audience
:
SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor()
{
Issuer= "whatever",
Audience= "whatever",
Subject = new ClaimsIdentity(new[] { new Claim("UserName", user.Name) }),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(encryptionKey, SecurityAlgorithms.HmacSha256Signature)
};
另一種方法是您可以將ValidateIssuer
和ValidateAudience
設置為 false:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false, //change here..
ValidIssuer = "whatever",
ValidateAudience = false, //change here..
ValidAudience = "whatever",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("TODO_Find_better_key_and_store_as_secret"))
};
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.