[英]Query Database for Role Authorization Before Each Action in ASP.NET Core
結合Identity的ASP.NET Core已經提供了一種在登錄后檢查角色的簡單方法,但我想在每個控制器操作之前向數據庫查詢當前用戶的當前角色。
我已經閱讀了Microsoft的基於角色,基於策略和聲明的授權。 ( https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction )這些解決方案似乎都沒有檢查每個操作的角色。 以下是我最近嘗試以某種基於策略的授權的形式實現預期結果:
在Startup.cs中:
DatabaseContext context = new DatabaseContext();
services.AddAuthorization(options =>
{
options.AddPolicy("IsManager",
policy => policy.Requirements.Add(new IsManagerRequirement(context)));
options.AddPolicy("IsAdmin",
policy => policy.Requirements.Add(new IsAdminRequirement(context)));
});
在我的需求文件中:
public class IsAdminRequirement : IAuthorizationRequirement
{
public IsAdminRequirement(DatabaseContext context)
{
_context = context;
}
public DatabaseContext _context { get; set; }
}
public class IsAdminHandler : AuthorizationHandler<IsAdminRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsAdminRequirement requirement)
{
// Enumerate all current users roles
int userId = Int32.Parse(context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value);
Roles adminRoles = requirement._context.Roles.FirstOrDefault(r => r.Name == "Administrator" && r.IsActive == true);
bool hasRole = requirement._context.UserRoles.Any(ur => ur.UserId == userId && adminRoles.Id == ur.RoleId && ur.IsActive == true);
// Check for the correct role
if (hasRole)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
並在控制器中:
[HttpGet]
[Authorize(Policy = "IsAdmin")]
public async Task<IActionResult> Location()
{
// do action here
}
使用此代碼,需求中間件以某種方式永遠不會被調用,因此永遠不會檢查數據庫。
在執行每個控制器操作之前,如何正確查詢數據庫以檢查當前用戶的角色?
我通過處理OnTokenValidated事件在我的應用程序(SignalR + JwtBearer)中解決了這個問題。 我只是檢查聲明中的角色與我的數據庫中的角色。 如果它們不再有效,我將TokenValidatedContext設置為失敗。
這是我的ASP.NET核心Startup.cs的摘錄:
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.Events = new JwtBearerEvents
{
OnTokenValidated = async context =>
{
var userService = context.HttpContext.RequestServices.GetRequiredService<IUserRoleStore<User>>();
var username = context.Principal.Identity.Name;
var user = await userService.FindByNameAsync(username, CancellationToken.None);
if (user == null)
{
// return unauthorized if user no longer exists
context.Fail("Unauthorized");
}
else
{
// Check if the roles are still valid.
var roles = await userService.GetRolesAsync(user, CancellationToken.None);
foreach (var roleClaim in context.Principal.Claims.Where(p => p.Type == ClaimTypes.Role))
{
if (roles.All(p => p != roleClaim.Value))
{
context.Fail("Unauthorized");
return;
}
}
context.Success();
}
},
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.