ASP.NET Core与Identity相结合已经提供了一种在登录后检查角色的简单方法,但我想在每个控制器操作之前向数据库查询当前用户的当前角色。
我已经阅读了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
}
使用此代码,需求中间件以某种方式永远不会被调用,因此永远不会检查数据库。
在执行每个控制器操作之前,如何正确查询数据库以检查当前用户的角色?
答案 0 :(得分:1)
我通过处理OnTokenValidated事件在应用程序(SignalR + JwtBearer)中解决了此问题。我只是将索赔中的角色与数据库中的角色进行核对。如果它们不再有效,则将TokenValidatedContext设置为失败。
以下是我的ASP.NET Core 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
};
});