EPR类企业管理系统

在我们现有系统基础上或全新开发,提供定制服务
为您的企业高效快速实施ERP,WMS,MES,CRM管理系统
全面管控物料仓库、销售业务、采购业务、仓库业务
生产过程、质量检验、组织架构、业务报表


定制
QQ:460-3528

开发
QQ群:3360-90194

源码
微信:136-3650-3721

如何:实施可以在类型级别上允许的自定义安全操作

在XAF安全系统中,默认情况下可以对特定类型允许以下操作:读取写入创建删除。在本主题中,显示了其他导出操作的实现。还演示了ExportController的定制,该定制应考虑当前显示的对象类型是允许还是拒绝Export操作。

移动应用程序不支持ExportController。但是,您可以实现本主题中描述的方法以允许或拒绝其他操作。

ExportOperation_Result

提示

DevExpress代码示例数据库(http://www.devexpress.com/example=E4483)中提供了完整的示例项目。

注意

如果要一次在角色级别上允许所有类型的导出功能,请参阅如何:实现自定义安全对象(用户,角色,操作权限)主题。

定制安全系统

  • 使用AllowExport属性扩展用于存储权限的PermissionPolicyTypePermissionObject持久对象。

    using DevExpress.ExpressApp.DC;
    using DevExpress.Persistent.Base;
    using DevExpress.Persistent.BaseImpl.PermissionPolicy;
    // ...
    [XafDisplayName("Type Operation Permissions")]
    public class CustomTypePermissionObject : PermissionPolicyTypePermissionObject {
        public CustomTypePermissionObject(Session session)
            : base(session) {
        }
        [XafDisplayName("Export")]
        public SecurityPermissionState? ExportState {
            get {
                return GetPropertyValue<SecurityPermissionState?>(nameof(ExportState));
            }
            set {
                SetPropertyValue(nameof(ExportState), value);
            }
        }
    }
    
  • 要实现自定义的操作权限,请添加支持IOperationPermission接口的类。

    using DevExpress.ExpressApp.Security;
    using DevExpress.Persistent.Base;
    // ...
    public class ExportPermission : IOperationPermission {
        public ExportPermission(Type objectType, SecurityPermissionState state) {
            ObjectType = objectType;
            State = state;
        }
        public Type ObjectType { get; private set; }
        public string Operation { get { return "Export"; } }
        public SecurityPermissionState State { get; set; }
    }
    
  • 安全系统使用权限请求来确定是否授予权限。为ExportPermission权限添加一个权限请求。通过以下方式实现IPermissionRequest接口。

    using DevExpress.ExpressApp.Security;
    // ...
    public class ExportPermissionRequest : IPermissionRequest {
        public ExportPermissionRequest(Type objectType) {
            ObjectType = objectType;
        }
        public Type ObjectType { get; private set; }
        public object GetHashObject() {
            return ObjectType.FullName;
        }
    }
    
  • 所有权限请求都应具有安全策略已知的适当权限请求处理器。要实现这种处理器,请继承PermissionRequestProcessorBase <ProcessorPermissionRequestType>类,然后将Permission Request类型作为祖先类的通用参数传递。

    using System.Linq;
    using System.Collections.Generic;
    using DevExpress.ExpressApp.Security;
    using DevExpress.Persistent.Base;
    // ...
    public class ExportPermissionRequestProcessor : PermissionRequestProcessorBase<ExportPermissionRequest> {
        private IPermissionDictionary permissionDictionary;
        public ExportPermissionRequestProcessor(IPermissionDictionary permissionDictionary) {
            this.permissionDictionary = permissionDictionary;
        }
        public override bool IsGranted(ExportPermissionRequest permissionRequest) {
            IEnumerable<ExportPermission> exportPermissions = 
                permissionDictionary.GetPermissions<ExportPermission>().Where(p => p.ObjectType == permissionRequest.ObjectType);
            if (exportPermissions.Count() == 0) {
                return IsGrantedByPolicy(permissionDictionary);
            }
            else {
                return exportPermissions.Any(p => p.State == SecurityPermissionState.Allow);
            }
        }
        private bool IsGrantedByPolicy(IPermissionDictionary permissionDictionary) {
            if (GetPermissionPolicy(permissionDictionary) == SecurityPermissionPolicy.AllowAllByDefault) {
                return true;
            }
            return false;
        }
        private SecurityPermissionPolicy GetPermissionPolicy(IPermissionDictionary permissionDictionary) {
            SecurityPermissionPolicy result = SecurityPermissionPolicy.DenyAllByDefault;
            List<SecurityPermissionPolicy> permissionPolicies = 
                permissionDictionary.GetPermissions<PermissionPolicy>().Select(p => p.SecurityPermissionPolicy).ToList();
            if (permissionPolicies != null && permissionPolicies.Count != 0) {
                if (permissionPolicies.Any(p => p == SecurityPermissionPolicy.AllowAllByDefault)) {
                    result = SecurityPermissionPolicy.AllowAllByDefault;
                }
                else {
                    if (permissionPolicies.Any(p => p == SecurityPermissionPolicy.ReadOnlyAllByDefault)) {
                        result = SecurityPermissionPolicy.ReadOnlyAllByDefault;
                    }
                }
            }
            return result;
        }
    }
    
  • 在WinForms应用程序项目的Program.cs(Program.vb)文件和ASP.NET应用程序项目的Global.asax.cs(Global.asax.vb)文件中处理SecurityStrategy.CustomizeRequestProcessors事件,以注册ExportPermissionRequestProcessor。在调用XafApplication.Setup方法之前订阅此事件。使用中间层应用程序服务器时,无需在客户端上处理此事件。而是,在服务器的Program.cs(Program.vb)文件中订阅此事件。

    ((SecurityStrategy)winApplication.Security).CustomizeRequestProcessors  = CustomizeRequestProcessors;
    // ...
    private static void CustomizeRequestProcessors(object sender, CustomizeRequestProcessorsEventArgs e) {
        List<IOperationPermission> result = new List<IOperationPermission>();
        SecurityStrategyComplex security = sender as SecurityStrategyComplex;
        if (security != null) {
            PermissionPolicyUser user = security.User as PermissionPolicyUser;
            if (user != null) {
                foreach (PermissionPolicyRole role in user.Roles) {
                    foreach (PermissionPolicyTypePermissionObject persistentPermission in role.TypePermissions) {
                        CustomTypePermissionObject customPermission = persistentPermission as CustomTypePermissionObject;
                        if (customPermission != null && customPermission.ExportState != null) {
                            SecurityPermissionState state = (SecurityPermissionState)customPermission.ExportState;
                            result.Add(new ExportPermission(customPermission.TargetType, state));
                        }
                    }
                }
            }
        }
        IPermissionDictionary permissionDictionary = new PermissionDictionary(result);
        e.Processors.Add(typeof(ExportPermissionRequest), new ExportPermissionRequestProcessor(permissionDictionary));
    }
    
  • 在“中间层安全性-WCF服务”方案中,您还应该通过静态WcfDataServerHelper.AddKnownType方法注册自定义权限请求。在初始化数据服务器和客户端应用程序之前,在应用程序服务器和客户端应用程序代码中均调用此方法。

    WcfDataServerHelper.AddKnownType(typeof(ExportPermissionRequest));
    

创建预定义的用户和角色

要检查已实施的导出操作,请将具有适当角色的预定义Admin和User用户添加到应用程序的数据库中。编辑位于模块项目的DatabaseUpdate文件夹中的Updater.csUpdater.vb)文件。以以下方式重写ModuleUpdater.UpdateDatabaseAfterUpdateSchema方法。

using DevExpress.Persistent.BaseImpl.PermissionPolicy;
// ...
public override void UpdateDatabaseAfterUpdateSchema() {
    base.UpdateDatabaseAfterUpdateSchema();
    PermissionPolicyUser admin = ObjectSpace.FindObject<PermissionPolicyUser>(new BinaryOperator("UserName", "Admin"));
    if (admin == null) {
        admin = ObjectSpace.CreateObject<PermissionPolicyUser>();
        admin.UserName = "Admin";
        admin.SetPassword("");
        PermissionPolicyRole adminRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
        adminRole.Name = "Administrator Role";
        adminRole.IsAdministrative = true;
        admin.Roles.Add(adminRole);
    }
    PermissionPolicyUser user = ObjectSpace.FindObject<PermissionPolicyUser>(new BinaryOperator("UserName", "User"));
    if (user == null) {
        user = ObjectSpace.CreateObject<PermissionPolicyUser>();
        user.UserName = "User";
        user.SetPassword("");
        PermissionPolicyRole userRole = ObjectSpace.CreateObject<PermissionPolicyRole>();
        userRole.Name = "User Role";
        CustomTypePermissionObject taskTypePermission = ObjectSpace.CreateObject<CustomTypePermissionObject>();
        taskTypePermission.TargetType = typeof(Task);
        taskTypePermission.CreateState = SecurityPermissionState.Allow;
        taskTypePermission.DeleteState = SecurityPermissionState.Allow;
        taskTypePermission.NavigateState = SecurityPermissionState.Allow;
        taskTypePermission.ReadState = SecurityPermissionState.Allow;
        taskTypePermission.WriteState = SecurityPermissionState.Allow;
        taskTypePermission.ExportState = SecurityPermissionState.Allow;
        CustomTypePermissionObject userTypePermission = ObjectSpace.CreateObject<CustomTypePermissionObject>();
        userTypePermission.TargetType = typeof(PermissionPolicyUser);
        userTypePermission.NavigateState = SecurityPermissionState.Allow;
        userTypePermission.ReadState = SecurityPermissionState.Allow;
        userRole.TypePermissions.Add(taskTypePermission);
        userRole.TypePermissions.Add(userTypePermission);
        user.Roles.Add(userRole);
    }
    ObjectSpace.CommitChanges();
    for (int i = 1; i <= 10; i  ) {
        string subject = string.Format("Task {0}", i);
        Task task = ObjectSpace.FindObject<Task>(new BinaryOperator("Subject", subject));
        if (task == null) {
            task = ObjectSpace.CreateObject<Task>();
            task.Subject = subject;
            task.DueDate = DateTime.Today;
            task.Save();
        }
    }
    ObjectSpace.CommitChanges();
}

如您所见,允许User用户导出Task对象。不允许该用户导出PermissionPolicyUser对象。在这里,假定业务类库中的Task对象已添加到您的业务模型中(请参阅从业务类库中添加类)。在此示例中,您可以使用任何其他业务类来代替Task

验证是否允许当前用户执行自定义操作

若要让ExportController控制器及其ExportController.ExportAction Action知道Export操作的存在,请添加以下View Controller。

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.SystemModule;
// ...
public class SecuredExportController : ObjectViewController {
    private ExportController exportController;
    protected override void OnActivated() {
        base.OnActivated();
        exportController = Frame.GetController<ExportController>();
        if (exportController  != null) {
            exportController.ExportAction.Executing  = ExportAction_Executing;
            if (SecuritySystem.Instance is IRequestSecurity) {
                exportController.Active.SetItemValue("Security",
                    SecuritySystem.IsGranted(new ExportPermissionRequest(View.ObjectTypeInfo.Type)));
            }
        }
    }
    void ExportAction_Executing(object sender, System.ComponentModel.CancelEventArgs e) {
        SecuritySystem.Demand(new ExportPermissionRequest(View.ObjectTypeInfo.Type));
    }
}

该控制器订阅Export Action的ActionBase.Executing事件,并调用SecuritySystem.Demand方法以检查在执行导出之前是否允许Export操作。如果不允许当前用户导出当前视图中显示的对象,则会引发异常。要对其进行测试,请运行该应用程序,以User身份登录,导航到用户列表,然后尝试执行Export Action。

您可能要避免安全异常,并在不允许导出时禁用导出操作。在这种情况下,请另外重写OnViewChanged方法,并根据SecuritySystem.IsGranted方法结果更改Action的可见性。

public class SecuredExportController : ObjectViewController {
    // ....
    protected override void OnViewChanged() {
        base.OnViewChanged();
        if (exportController != null) {
            exportController.ExportAction.Active.SetItemValue("Security",
                SecuritySystem.IsGranted(new ExportPermissionRequest(View.ObjectTypeInfo.Type)));
        }
    }
}

如果您运行该应用程序并以User身份登录,您将看到“导出”操作对于“任务”对象是活动的,而对于“ PermissionPolicyUser”对象则是隐藏的。

调整管理界面

如果打开“角色详细信息视图”并选择“类型权限”选项卡,则在嵌套列表视图中将看不到“导出”列。此列表视图的对象类型为PermissionPolicyTypePermissionObject,而AllowExport属性在派生的CustomTypePermissionObject类中声明。要显示“导出”列,请使用UpCasting。调用模型编辑器,导航到PermissionPolicyRoleBase_TypePermissions_ListView节点并添加ExportState列。将PropertyName设置为此列的<CustomTypePermissionObject> ExportState。下图说明了这种自定义。

ExportOperation_AddColumn

导航到CustomTypePermissionObject_DetailView节点,对其Layout进行以下调整:

  • 将操作复选框分组在一起;
  • TargetType属性移到顶部;

下图演示了所需的布局:

ExportOperation_Layout

您可能会注意到,伴随“类型权限列表”视图的“新建操作”包含重复的“类型操作权限”操作项。这些项目之一引用基本的PermissionPolicyTypePermissionObject类型,另一个引用您的自定义CustomTypePermissionObject。要隐藏基类的项目,请使用以下Controller自定义“新建操作”的项目列表。

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.SystemModule;
using DevExpress.Persistent.BaseImpl.PermissionPolicy;
// ...
public class RemoveBaseTypePermissionNewActionItemController :
    ObjectViewController<ObjectView, PermissionPolicyTypePermissionObject> {
    protected override void OnFrameAssigned() {
        NewObjectViewController newObjectViewController = Frame.GetController<NewObjectViewController>();
        if(newObjectViewController != null) {
            newObjectViewController.CollectDescendantTypes  = (s, e) => {
                e.Types.Remove(typeof(PermissionPolicyTypePermissionObject));
            };
            newObjectViewController.ObjectCreating  = (s, e) => {
                if(e.ObjectType == typeof(PermissionPolicyTypePermissionObject)) {
                    e.NewObject = e.ObjectSpace.CreateObject(typeof(CustomTypePermissionObject));
                }
            };
        }
        base.OnFrameAssigned();
    }
}
相关文章

转载保留此链接,注明出处