如何解决在ASP.NET Core / Entity Framework Core 3.1
前提
在ASP.Net Core中应用基于资源的授权的已记录方法是注册一个AuthorizationHandler
,定义每个OperationAuthorizationRequirement
,然后使用一个AuthorizeAsync()
方法来检查对资源的访问注入了IAuthorizationHandler
。 (Reference docs)
这对于检查单个记录的操作是一件好事,但是我的问题是如何一次最好地对许多资源进行授权(例如,针对索引页的记录列表检查读取权限)?
示例
假设我们有一个订单列表,我们想为用户提供他们创建的订单列表。为此,请按照Microsoft文档定义的做法进行操作,我们首先创建一些静态OperationAuthorizationRequirement
对象:
public static class CrudOperations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement { Name = nameof(Create) };
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = nameof(Read) };
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement { Name = nameof(Update) };
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement { Name = nameof(Delete) };
}
..然后创建我们的AuthorizationHandler:
public class OrderCreatorAuthorizationHandler :
AuthorizationHandler<OperationAuthorizationRequirement,Order>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,OperationAuthorizationRequirement requirement,InspectionManagementUser resource)
{
if (context.User == null || resource == null)
{
return Task.CompletedTask;
}
var currentUserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (resource.CreatedById == currentUserId
&& requirement.Name == CrudOperations.Read.Name) {
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
这已在Startup.cs
中注册为服务,并且可以使用了。在我们的视图逻辑中,我们可以使用新的处理程序来获取如下的订单过滤列表:
//_context is an injected instance of the application's DatabaseContext
//_authorizationService is an injected instance of IAuthorizationService
var allOrders = await _context.Orders.ToListAsync();
var filteredOrders = allOrders
.Where(o => _authorizationService.AuthorizeAsync(User,o,CrudOperations.Read).Result.Succeeded);
这将很好地工作,但是在我看来,由于每个记录都是在内存中单独检查的,因此在计算上非常昂贵。随着授权处理程序的逻辑变得更加复杂(例如,如果它涉及数据库调用),这将进一步增加。
让数据库引擎为我们过滤列表的方式大概效率更高:
var currentUserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var filteredOrders = await _context.Orders
.Where(o => o.CreatedById == currentUserId)
.ToListAsync();
这将执行得更快,但是我们现在已经完全绕过了授权逻辑。如果我们以后决定更改AuthorizationHandler
中的限制,我们还必须记住要在此处和其他使用此方法的其他地方进行更改。如果您问我,这似乎违反了首先将授权代码分离出来的目的。
是否有解决此问题的灵巧解决方案?任何关于最佳实践的建议或指导将不胜感激。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。