高级权限管理 - 依赖于角色和实体

时间:2017-07-27 01:56:30

标签: .net model-view-controller

这是一个相当先进的设计问题,我似乎找不到简单的答案。

类似于这个问题: Manage entity access and permissions with Entity Framework

系统的纤薄版本:

  1. 我们在3个类别中有6种不同的用户。

    • 供应商:用户
    • 供应商:管理员用户
    • InternalFactory:用户
    • InternalFactory:管理员用户
    • 管理员:维护用户
    • 管理员:超级用户 Admin,Supplier和InternalFactory组都是互斥的。
  2. 我们有一个允许用户编辑实体的页面。让我们使用"发货"举个例子。货件仅由供应商或管理员创建。只有......才能编辑货件。

    • 这是编辑的最后一批货件(适用于除管理员角色以外的所有角色。)
    • 它由与用户(适用于供应商角色)相同的供应商公司所有。
    • 它由与用户InternalFactory相关的供应商公司所有。 (仅适用于InternalFactory角色)
  3. 所以问题是,编辑权限取决于对象的属性以及用户角色。所以我的代码最终变得非常混乱而且我经常犯错误 - 这是一些不同代码的摘录,所以你明白了。我没有实现我上面所说的内容。

    权限被授予某些角色,这些角色可能以错误的方式使用,然后根据实体属性确定其他内容以查看它是否是"我们的"装运等

     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"功能不好而且合乎逻辑。我希望在设计方面有更好的东西;关于如何在“最佳实践”中处理此问题的教程或讲座或解释。那种方式。

    感谢。

1 个答案:

答案 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按钮等。