EPR类企业管理系统

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


定制
QQ:460-3528

开发
QQ群:3360-90194

源码
微信:136-3650-3721

如何:实现自定义安全对象(用户,角色,操作权限)

本示例说明了如何创建自定义安全对象,例如权限,角色和用户。您可以实现管理员用来允许或拒绝用户在XAF应用程序中导出数据的权限。每个角色都公开CanExport属性(为此目的实现了自定义角色对象)。选中相应的复选框后,与此角色关联的用户可以访问ExportController.ExportAction操作。

移动应用程序不支持ExportAction。但是,您可以实施本主题中描述的方法来保护其他操作。

注意

本示例仅适用于XPO应用程序。您应该修改本主题中的代码段以在EF应用程序中使用它:

请参阅带有实体框架的业务模型设计主题,以获取有关EF数据模型设计的更多信息。

提示

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

实现自定义角色和用户对象

  • 用附加的CanExport属性扩展PermissionPolicyRole类。这表明角色具有ExportPermission。

    using DevExpress.Persistent.BaseImpl.PermissionPolicy;
    // ...
    [DefaultClassOptions, ImageName("BO_Role")]
    public class ExtendedSecurityRole : PermissionPolicyRole {
        public ExtendedSecurityRole(Session session) : base(session) { }
        public bool CanExport {
            get { return GetPropertyValue<bool>(nameof(CanExport)); }
            set { SetPropertyValue<bool>(nameof(CanExport), value); }
        }
    }
    
  • 将“可以导出”项放置在ExtendedSecurityRole的“详细信息”视图布局上(请参阅“查看项目布局定制”)。

    CustomPermission_ModelEditor

  • 下面的代码片段演示了自定义User对象的实现。您可以执行此附加任务,以使此示例更加实际。但是,不需要自定义User的实现以支持ExportPermission

    using DevExpress.Persistent.BaseImpl.PermissionPolicy;
    // ...
    [DefaultClassOptions, ImageName("BO_Employee")]
    public class Employee : PermissionPolicyUser {
        public Employee(Session session)
            : base(session) { }
        [Association("Employee-Task")]
        public XPCollection<Task> Tasks {
            get { return GetCollection<Task>(nameof(Tasks));  }
        }
    }
    [DefaultClassOptions, ImageName("BO_Task")]
    public class Task : BaseObject {
        public Task(Session session)
            : base(session) { }
        private string subject;
        public string Subject {
            get { return subject; }
            set { SetPropertyValue(nameof(Subject), ref subject, value); }
        }
        private DateTime dueDate;
        public DateTime DueDate {
            get { return dueDate; }
            set { SetPropertyValue(nameof(DueDate), ref dueDate, value); }
        }
        private Employee assignedTo;
        [Association("Employee-Task")]
        public Employee AssignedTo {
            get { return assignedTo; }
            set { SetPropertyValue(nameof(AssignedTo), ref assignedTo, value); }
        }
    }
    
  • 调用应用程序设计器,然后将SecurityStrategyComplexAuthenticationStandard组件从“工具箱”拖到“安全性”窗格上。在“属性”窗口中修改SecurityStrategyComplex.RoleTypeSecurityStrategy.UserType值,以使用实现的ExtendedSecurityRole和Employee对象代替默认的PermissionPolicyUser和PermissionPolicyRole。

    CustomPermission_AppDesigner

实施自定义操作权限和权限请求

  • 添加支持IOperationPermission接口的类以实现自定义操作权限。

    using DevExpress.ExpressApp.Security;
    // ...
    public class ExportPermission : IOperationPermission {
        public string Operation { 
            get { return "Export"; }
        }
    }
    
  • 安全系统使用权限请求来确定是否授予权限。要为ExportPermission添加一个权限请求,请实现IPermissionRequest接口,如下所示:

    public class ExportPermissionRequest : IPermissionRequest {
        public object GetHashObject() {
            return this.GetType().FullName;
        }
    }
    

实施权限请求处理器并在安全策略中进行注册

  • 所有权限请求都应在安全策略中注册适当的权限请求处理器。继承PermissionRequestProcessorBase <ProcessorPermissionRequestType>类,并将Permission Request类型作为祖先类的通用参数传递,以将类实现为处理器。

    public class ExportPermissionRequestProcessor : 
        PermissionRequestProcessorBase<ExportPermissionRequest> {
        private IPermissionDictionary permissions;
        public ExportPermissionRequestProcessor(IPermissionDictionary permissions) {
            this.permissions = permissions;
        }
        public override bool IsGranted(ExportPermissionRequest permissionRequest) {
            return (permissions.FindFirst<ExportPermission>() != null);
        }
    }
    
  • 在WinForms应用程序项目的Program.cs(Program.vb)文件和ASP.NET应用程序项目的Global.asax.cs(Global.asax.vb)文件中处理SecurityStrategy.CustomizeRequestProcessors事件,以注册ExportPermissionRequestProcessor。在调用XafApplication.Setup方法之前订阅此事件。使用中间层应用程序服务器时,无需在客户端上处理此事件。而是,在服务器的Program.cs(Program.vb)文件中订阅此事件。在事件处理程序中,传递ExportPermission对象到PermissionDictionary

    Windows表格

    ((SecurityStrategy)winApplication.Security).CustomizeRequestProcessors  =
        delegate(object sender, CustomizeRequestProcessorsEventArgs e) {
            List<IOperationPermission> result = new List<IOperationPermission>();
            SecurityStrategyComplex security = sender as SecurityStrategyComplex;
            if (security != null) {
                Employee user = security.User as Employee;
                if (user != null) {
                    foreach (ExtendedSecurityRole role in user.Roles) {
                        if (role.CanExport) {
                            result.Add(new ExportPermission());
                        }
                    }
                }
            }
            IPermissionDictionary permissionDictionary = new PermissionDictionary((IEnumerable<IOperationPermission>)result);
            e.Processors.Add(typeof(ExportPermissionRequest), new ExportPermissionRequestProcessor(permissionDictionary));
        }; 
    winApplication.Setup();
    winApplication.Start();
    

    ASP.NET

    ((SecurityStrategy)WebApplication.Instance.Security).CustomizeRequestProcessors  =
        delegate(object s, CustomizeRequestProcessorsEventArgs args) {
            List<IOperationPermission> result = new List<IOperationPermission>();
            SecurityStrategyComplex security = s as SecurityStrategyComplex;
            if (security != null) {
                Employee user = security.User as Employee;
                if (user != null) {
                    foreach (ExtendedSecurityRole role in user.Roles) {
                        if (role.CanExport) {
                            result.Add(new ExportPermission());
                        }
                    }
                }
            }
            IPermissionDictionary permissionDictionary = new PermissionDictionary((IEnumerable<IOperationPermission>)result);
            args.Processors.Add(typeof(ExportPermissionRequest), new ExportPermissionRequestProcessor(permissionDictionary));
        };
    WebApplication.Instance.Setup();
    WebApplication.Instance.Start();
    

    应用服务器

    static void Main(string[] args) {
        // ...
        Func<IDataServerSecurity> dataServerSecurityProvider = () => {
            SecurityStrategyComplex security = new SecurityStrategyComplex(
                typeof(Employee), typeof(ExtendedSecurityRole), new AuthenticationStandard());
            security.CustomizeRequestProcessors  =
                delegate(object sender, CustomizeRequestProcessorsEventArgs e) {
                    List<IOperationPermission> result = new List<IOperationPermission>();
                    if (security != null) {
                        Employee user = security.User as Employee;
                        if (user != null) {
                            foreach (ExtendedSecurityRole role in user.Roles) {
                                if (role.CanExport) {
                                    result.Add(new ExportPermission());
                                }
                            }
                        }
                    }
                    IPermissionDictionary permissionDictionary = new PermissionDictionary((IEnumerable<IOperationPermission>)result);
                    e.Processors.Add(typeof(ExportPermissionRequest), new ExportPermissionRequestProcessor(permissionDictionary));
                }; 
            return security;
        };
        // ...
    }
    

    在“中间层安全性-WCF服务”方案中,您还应该使用静态WcfDataServerHelper.AddKnownType方法注册您的自定义权限请求。在初始化数据服务器和客户端应用程序之前,请在应用程序服务器和客户端应用程序代码中调用此方法。

    WcfDataServerHelper.AddKnownType(typeof(ExportPermissionRequest));
    

在ExportController控制器中考虑自定义权限

添加以下视图控制器,以将ExportPermission权限通知ExportController控制器:

public class SecuredExportController : ViewController {
    protected override void OnActivated() {
        base.OnActivated();
        ExportController controller = Frame.GetController<ExportController>();
        if (controller != null) {
            controller.ExportAction.Executing  = ExportAction_Executing;
            if(SecuritySystem.Instance is IRequestSecurity) {
                controller.Active.SetItemValue("Security", 
                    SecuritySystem.IsGranted(new ExportPermissionRequest()));
            }
        }
    }
    void ExportAction_Executing(object sender, System.ComponentModel.CancelEventArgs e) {
        SecuritySystem.Demand(new ExportPermissionRequest());
    }
}
  • 上面的代码为不允许导出数据的用户禁用了控制器。该ActionBase.Executing事件处理程序演示了如何抛出一个异常,当用户试图执行禁止的操作。

添加演示数据

如下所示,在ModuleUpdater.UpdateDatabaseAfterUpdateSchema方法中添加预定义的用户角色对象(请参阅客户端安全性(2-层体系结构))。

public class Updater : ModuleUpdater {
    public Updater(IObjectSpace objectSpace, Version currentDBVersion) : 
        base(objectSpace, currentDBVersion) { }
    public override void UpdateDatabaseAfterUpdateSchema() {
        base.UpdateDatabaseAfterUpdateSchema();
        ExtendedSecurityRole defaultRole = CreateUserRole();
        ExtendedSecurityRole administratorRole = CreateAdministratorRole();
        ExtendedSecurityRole exporterRole = CreateExporterRole();
        Employee userAdmin = ObjectSpace.FindObject<Employee>(new BinaryOperator("UserName", "Admin"));
        if (userAdmin == null) {
            userAdmin = ObjectSpace.CreateObject<Employee>();
            userAdmin.UserName = "Admin";
            userAdmin.IsActive = true;
            userAdmin.SetPassword("");
            userAdmin.Roles.Add(administratorRole);
        }
        Employee userSam = ObjectSpace.FindObject<Employee>(new BinaryOperator("UserName", "Sam"));
        if (userSam == null) {
            userSam = ObjectSpace.CreateObject<Employee>();
            userSam.UserName = "Sam";
            userSam.IsActive = true;
            userSam.SetPassword("");
            userSam.Roles.Add(exporterRole);
            userSam.Roles.Add(defaultRole);
        }
        Employee userJohn = ObjectSpace.FindObject<Employee>(new BinaryOperator("UserName", "John"));
        if (userJohn == null) {
            userJohn = ObjectSpace.CreateObject<Employee>();
            userJohn.UserName = "John";
            userJohn.IsActive = true;
            userJohn.Roles.Add(defaultRole);
            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();
                    userJohn.Tasks.Add(task);
                }
            }
        }
        ObjectSpace.CommitChanges();
    }
    private ExtendedSecurityRole CreateAdministratorRole() {
        ExtendedSecurityRole administratorRole = ObjectSpace.FindObject<ExtendedSecurityRole>(
            new BinaryOperator("Name", SecurityStrategyComplex.AdministratorRoleName));
        if (administratorRole == null) {
            administratorRole = ObjectSpace.CreateObject<ExtendedSecurityRole>();
            administratorRole.Name = SecurityStrategyComplex.AdministratorRoleName;
            administratorRole.IsAdministrative = true;
        }
        return administratorRole;
    }
    private ExtendedSecurityRole CreateExporterRole() {
        ExtendedSecurityRole exporterRole = ObjectSpace.FindObject<ExtendedSecurityRole>(
            new BinaryOperator("Name", "Exporter"));
        if (exporterRole == null) {
            exporterRole = ObjectSpace.CreateObject<ExtendedSecurityRole>();
            exporterRole.Name = "Exporter";
            exporterRole.CanExport = true;
        }
        return exporterRole;
    }
    private ExtendedSecurityRole CreateUserRole() {
        ExtendedSecurityRole userRole = ObjectSpace.FindObject<ExtendedSecurityRole>(
            new BinaryOperator("Name", "Default"));
        if (userRole == null) {
            userRole = ObjectSpace.CreateObject<ExtendedSecurityRole>();
            userRole.Name = "Default";
            userRole.SetTypePermission<Task>(SecurityOperations.FullAccess, SecurityPermissionState.Allow);
            userRole.SetTypePermission<Employee>(SecurityOperations.ReadOnlyAccess, SecurityPermissionState.Allow);
            userRole.AddObjectPermission<PermissionPolicyUser>(SecurityOperations.ReadOnlyAccess,
                 "[Oid] = CurrentUserId()", SecurityPermissionState.Allow);
        }
        return userRole;
    }
}

确认应用程序用户界面根据角色进行了更改

运行WinForms或ASP.NET应用程序,然后以“管理员”身份登录。打开扩展安全角色对象的详细信息视图。在“可以导出”复选框中选中“导出器”角色。

CustomPermission_CanExport

再次以“ Sam”(具有“出口商”角色)身份登录。确保“导出”操作可用于该用户。如果您以“ John”身份登录,则“导出”操作不可用。

CustomPermission_ExportAction

提示

在大多数情况下,当自定义用户和角色(Employee和ExtendedSecurityRole)可用时,您不需要在UI中创建基本用户和基本角色对象(PermissionPolicyUserPermissionPolicyRole)的选项。若要隐藏基本用户和基本角色的项目,请使用NewObjectViewController.NewObjectActionItemListMode属性或“如何从“新操作的项目”列表中删除或隐藏基类”中列出的其他选项。

注意

出口措施可用于即使未选中“可导出”选项为“管理员”角色的“管理员”用户。“是管理”选项将覆盖所有其他权限(内置和自定义),并授予对所有操作的完全访问权限。

相关文章

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