[英].Net Core 2 JWT, Angular 2 Authorization through roles does not work
我在用 JWT 生成的令牌中有以下有用的負載
{ "sub": "flamelsoft@gmail.com", "jti": "0bca1034-f3ce-4f72-bd91-65c1a61924c4", " http://schemas.microsoft.com/ws/2008/06/identity/claims/角色":"管理員","exp":1509480891,"iss":" http://localhost:40528 ","aud":" http://localhost:40528 "}
使用此代碼 Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DBContextSCM>(options =>
options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), b =>
b.MigrationsAssembly("FlamelsoftSCM")));
services.AddIdentity<User, Role>()
.AddEntityFrameworkStores<DBContextSCM>()
.AddDefaultTokenProviders();
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
services.AddAuthentication()
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = Configuration["Tokens:Issuer"],
ValidAudience = Configuration["Tokens:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
};
});
services.AddMvc();
}
賬戶控制器.cs
[HttpPost]
[Authorize(Roles="Administrator")]
public async Task<IActionResult> Register([FromBody]RegisterModel model)
{
try
{
var user = new User { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var role = await _roleManager.FindByIdAsync(model.Role);
result = await _userManager.AddToRoleAsync(user, role.Name);
if (result.Succeeded)
return View(model);
}
return BadRequest($"Error: Could not create user");
}
catch (Exception ex)
{
return BadRequest($"Error: {ex.Message}");
}
}
用戶服務.ts
export class UserService {
constructor(private http: Http, private config: AppConfig, private currentUser: User) { }
create(user: User) {
return this.http.post(this.config.apiUrl + 'Account/Register', user, this.jwt());
}
private jwt() {
const userJson = localStorage.getItem('currentUser');
this.currentUser = userJson !== null ? JSON.parse(userJson) : new User();
if (this.currentUser && this.currentUser.token) {
let headers = new Headers({ 'Authorization': 'Bearer ' + this.currentUser.token });
return new RequestOptions({ headers: headers });
}
}}
問題是角色的驗證不起作用,請求到達控制器並在header中返回代碼200,但從未進入類。 當我刪除 [Authorize (Roles = "Administrator")] 時,它會正確輸入我的代碼。 有什么不好的定義嗎? 或者通過角色定義授權的替代方法是什么。
TL; DR
如原始問題的評論中所述,更改:
[HttpPost]
[Authorize(Roles = "Administrator")]
public async Task<IActionResult> Register([FromBody]RegisterModel model)
{
// Code
}
至
[HttpPost]
[Authorize(AuthenticationSchemes = "Bearer", Roles = "Administrator")]
public async Task<IActionResult> Register([FromBody]RegisterModel model)
{
// Code
}
解決了這個問題。
在ASP.NET Core中使用JWT承載認證時, Bearer
是默認的認證方案名稱 。
但是為什么我們需要在[Authorize]
屬性上指定AuthenticationSchemes
屬性?
這是因為配置身份驗證方案並不意味着它們將在每個HTTP請求上運行。 如果匿名用戶可以訪問特定操作,為什么還要從cookie或令牌中提取用戶信息呢? MVC對此非常聰明,並且只在需要時運行身份驗證處理程序,即在以某種方式受到保護的請求期間運行。
在我們的例子中,MVC發現[Authorize]
屬性,因此知道它必須運行身份驗證和授權來確定請求是否被授權。 訣竅在於它只運行已指定的身份驗證方案處理程序 。 在這里,我們沒有,所以沒有執行身份驗證,這意味着授權失敗,因為請求被認為是匿名的。
將身份驗證方案添加到屬性指示MVC以運行該處理程序,該處理程序從HTTP請求中的令牌中提取用戶信息,這導致發現Administrator
角色,並且允許該請求。
作為旁注,還有另一種方法可以實現這一點,而無需使用[Authorize]
屬性的AuthenticationSchemes
屬性。
想象一下,您的應用程序只配置了一個身份驗證方案,必須在每個[Authorize]
屬性上指定AuthenticationSchemes
屬性是一件痛苦的事。
使用ASP.NET Core,您可以配置默認的身份驗證方案。 這樣做意味着將為每個HTTP請求運行關聯的處理程序,無論資源是否受到保護。
設置它分為兩部分:
public class Startup
{
public void ConfiguresServices(IServiceCollection services)
{
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme /* this sets the default authentication scheme */)
.AddJwtBearer(options =>
{
// Configure options here
});
}
public void Configure(IApplicationBuilder app)
{
// This inserts the middleware that will execute the
// default authentication scheme handler on every request
app.UseAuthentication();
app.UseMvc();
}
}
這樣做意味着在MVC評估請求是否被授權時,已經進行了AuthenticationSchemes
,因此不指定[Authorize]
屬性的AuthenticationSchemes
屬性的任何值都不會有問題。
進程的授權部分仍將運行,並檢查經過身份驗證的用戶是否屬於Administrator
組。
我知道這個問題已經有了答案,但這里遺漏了一些重要的東西。 您需要確保您確實為登錄用戶設置了聲明。 就我而言,我使用的是 JWT 身份驗證,因此這一步非常重要:
var claims = new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, user.UserName) });
var roles = await _userManager.GetRolesAsync(user);
if (roles.Count > 0)
{
foreach (var role in roles) { claims.AddClaim(new Claim(ClaimTypes.Role, role)); }
}
var token = new JwtSecurityToken(
issuer: _configuration["JWT:Issuer"],
audience: _configuration["JWT:Audience"],
expires: DateTime.UtcNow.AddMinutes(15),
signingCredentials: signingCredentials,
claims: claims.Claims);
我正在努力弄清楚為什么HttpContext.User
沒有包含我期望縮小[Authroization(Roles="Admin")]
問題的范圍。 事實證明,如果您使用JWT身份驗證,您需要記住將Claims[]
設置為身份。 也許這是通過其他dotnet
方式自動完成的,但jwt
似乎要求您手動設置。
在我為用戶設置聲明后, [Authorize(Roles = "Whatever")]
按預期工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.