这是一个相当先进的设计问题,我似乎找不到简单的答案。
类似于这个问题: Manage entity access and permissions with Entity Framework
系统的纤薄版本:
我们在3个类别中有6种不同的用户。
我们有一个允许用户编辑实体的页面。让我们使用"发货"举个例子。货件仅由供应商或管理员创建。只有......才能编辑货件。
所以问题是,编辑权限取决于对象的属性以及用户角色。所以我的代码最终变得非常混乱而且我经常犯错误 - 这是一些不同代码的摘录,所以你明白了。我没有实现我上面所说的内容。
权限被授予某些角色,这些角色可能以错误的方式使用,然后根据实体属性确定其他内容以查看它是否是"我们的"装运等
public bool CheckCanEdit(EntityDto input)
{
if (
IsGranted(PermissionNames.EditAnyShipments)
||
(IsGranted(PermissionNames.EditShipments) && _shipmentsRepo.GetAllForEdit().Where(s =>
s.Id == input.Id && s.SupplierId == AbpSession.TenantId).Count() > 0
)
||
(IsGranted(PermissionNames.EditClientShipments) && _shipmentsRepo.GetAllForEdit().Where(s =>
s.Id == input.Id && s.FactoryId == AbpSession.TenantId).Count() > 0
)
)
{
return true;
}
return false;
}
这实际上是一个更简单的案例,但你可以看到它的去向。
我想要的是有一个我可以调用的简单方法,它会告诉我用户是否可以编辑实体。我已经实现了#34;可以轻松打电话"通过将此方法放入服务"发货"以及所有其他"更新"等功能。这很棒,因为我也可以从Api中调用它,UI可以获得相同的逻辑。
但我觉得这很重,而且很乱。 它很重,因为例如,如果我想加载100个货件的清单,并显示"编辑"按钮,它们都需要在UI知道显示按钮之前单独调用。 它很乱,因为" CheckCanEdit"功能不好而且合乎逻辑。我希望在设计方面有更好的东西;关于如何在“最佳实践”中处理此问题的教程或讲座或解释。那种方式。
感谢。
答案 0 :(得分:0)
此问题的一个解决方案是使用Specification Pattern,即实施shown here in ASP ABP
规范可以是:EditableShipments
在此规范中,根据用户具有的权限返回表达式。
public class EditableShipmentSpecification : Specification<Shipment>, ITransientDependency
{
private readonly IPermissionChecker _permiss;
public EditableShipmentSpecification(IPermissionChecker permis)
{
_permiss = permis;
}
public override Expression<Func<Shipment, bool>> ToExpression()
{
//if this is true, we can edit regardless
bool skipermission = _permiss.IsGranted(PermissionNames.AllowShipmentEditEvenIfInvoiced);
//Admins
if (_permiss.IsGranted(PermissionNames.FullEdit_Any_Shipment))
return (shipment) => (!shipment.IsDeleted);
//FactoryAdmins
// Only last is fully editable
if (_permiss.IsGranted(PermissionNames.CanEditLastShipment))
return (shipment) => !shipment.IsDeleted &&
shipment.Order.IsDeleted == false &&
shipment.Order.Shipment.Where(s => s.IsDeleted == false).Max(o => o.BatchNum) == shipment.BatchNum
&& (shipment.InvoiceId == null || skipermission)
;
//default
return (shipment) => (false);
}
}
这是我的解决方案,最终效果非常好,因为我们可以使用ToExpression
的{{1}}函数将其用作查询,或Specifications
函数进行快速比较用于在视图上启用IsSatisfiedBy
按钮等。