DevExpress_XPO_自定义安全对象(用户、角色、操作权限)
我们将学习如何创建自定义安全对象(包括角色、用户和权限)。
注:这个例子只适用于XPO应用程序。(要在EF应用程序中使用),请自行修改。
完整项目演示网址请参考官网。
实现自定义的角色和用户对象
- 角色继承PermissionPolicyRole类,使用附加属性CanExport。
1 using DevExpress.Persistent.BaseImpl.PermissionPolicy; 2 // ... 3 [DefaultClassOptions, ImageName("BO_Role")] 4 public class ExtendedSecurityRole : PermissionPolicyRole { 5 public ExtendedSecurityRole(Session session) : base(session) { } 6 public bool CanExport { 7 get { return GetPropertyValue<bool>("CanExport"); } 8 set { SetPropertyValue<bool>("CanExport", value); } 9 } 10 }
- 按照如下方式布局页面。
- 下面代码演示了自定义用户对象的实现。
1 using DevExpress.Persistent.BaseImpl.PermissionPolicy; 2 // ... 3 [DefaultClassOptions, ImageName("BO_Employee")] 4 public class Employee : PermissionPolicyUser { 5 public Employee(Session session) 6 : base(session) { } 7 [Association("Employee-Task")] 8 public XPCollection<Task> Tasks { 9 get { return GetCollection<Task>("Tasks"); } 10 } 11 } 12 [DefaultClassOptions, ImageName("BO_Task")] 13 public class Task : BaseObject { 14 public Task(Session session) 15 : base(session) { } 16 private string subject; 17 public string Subject { 18 get { return subject; } 19 set { SetPropertyValue("Subject", ref subject, value); } 20 } 21 private DateTime dueDate; 22 public DateTime DueDate { 23 get { return dueDate; } 24 set { SetPropertyValue("DueDate", ref dueDate, value); } 25 } 26 private Employee assignedTo; 27 [Association("Employee-Task")] 28 public Employee AssignedTo { 29 get { return assignedTo; } 30 set { SetPropertyValue("AssignedTo", ref assignedTo, value); } 31 } 32 }
- 调用应用程序设计器,并按照下图所示拖拽主键。修改AuthenticationStandard的RoleType和UserType。
实现自定义操作权限和权限请求
- 继承接口IOperationPermission。
1 using DevExpress.ExpressApp.Security; 2 // ... 3 public class ExportPermission : IOperationPermission { 4 public string Operation { 5 get { return "Export"; } 6 } 7 }
- 要实现添加权限请求,需要实现IPermissionRequest接口。
1 public class ExportPermissionRequest : IPermissionRequest { 2 public object GetHashObject() { 3 return this.GetType().FullName; 4 } 5 }
在安全策略中实现权限请求处理器
- 所有权限请求都应该在安全策略中注册适当的权限请求处理器。继承PermissionRequestProcessorBase类,并将权限请求类型作为祖先类的泛型参数传递,以实现一个类作为处理器。
1 public class ExportPermissionRequestProcessor : 2 PermissionRequestProcessorBase<ExportPermissionRequest> { 3 private IPermissionDictionary permissions; 4 public ExportPermissionRequestProcessor(IPermissionDictionary permissions) { 5 this.permissions = permissions; 6 } 7 public override bool IsGranted(ExportPermissionRequest permissionRequest) { 8 return (permissions.FindFirst<ExportPermission>() != null); 9 } 10 }
- 在事件处理程序中,将ExportPermission对象传递给PermissionDictionary。
Win版本(Global.asax.cs (Global.asax.vb))
1 ((SecurityStrategy)winApplication.Security).CustomizeRequestProcessors += 2 delegate(object sender, CustomizeRequestProcessorsEventArgs e) { 3 List<IOperationPermission> result = new List<IOperationPermission>(); 4 SecurityStrategyComplex security = sender as SecurityStrategyComplex; 5 if (security != null) { 6 Employee user = security.User as Employee; 7 if (user != null) { 8 foreach (ExtendedSecurityRole role in user.Roles) { 9 if (role.CanExport) { 10 result.Add(new ExportPermission()); 11 } 12 } 13 } 14 } 15 IPermissionDictionary permissionDictionary = new PermissionDictionary((IEnumerable<IOperationPermission>)result); 16 e.Processors.Add(typeof(ExportPermissionRequest), new ExportPermissionRequestProcessor(permissionDictionary)); 17 }; 18 winApplication.Setup(); 19 winApplication.Start();
ASP.NET版本(Program.cs (Program.vb))
1 ((SecurityStrategy)WebApplication.Instance.Security).CustomizeRequestProcessors += 2 delegate(object s, CustomizeRequestProcessorsEventArgs args) { 3 List<IOperationPermission> result = new List<IOperationPermission>(); 4 SecurityStrategyComplex security = s as SecurityStrategyComplex; 5 if (security != null) { 6 Employee user = security.User as Employee; 7 if (user != null) { 8 foreach (ExtendedSecurityRole role in user.Roles) { 9 if (role.CanExport) { 10 result.Add(new ExportPermission()); 11 } 12 } 13 } 14 } 15 IPermissionDictionary permissionDictionary = new PermissionDictionary((IEnumerable<IOperationPermission>)result); 16 args.Processors.Add(typeof(ExportPermissionRequest), new ExportPermissionRequestProcessor(permissionDictionary)); 17 }; 18 WebApplication.Instance.Setup(); 19 WebApplication.Instance.Start();
Application Server
1 static void Main(string[] args) { 2 // ... 3 Func<IDataServerSecurity> dataServerSecurityProvider = () => { 4 SecurityStrategyComplex security = new SecurityStrategyComplex( 5 typeof(Employee), typeof(ExtendedSecurityRole), new AuthenticationStandard()); 6 security.CustomizeRequestProcessors += 7 delegate(object sender, CustomizeRequestProcessorsEventArgs e) { 8 List<IOperationPermission> result = new List<IOperationPermission>(); 9 if (security != null) { 10 Employee user = security.User as Employee; 11 if (user != null) { 12 foreach (ExtendedSecurityRole role in user.Roles) { 13 if (role.CanExport) { 14 result.Add(new ExportPermission()); 15 } 16 } 17 } 18 } 19 IPermissionDictionary permissionDictionary = new PermissionDictionary((IEnumerable<IOperationPermission>)result); 20 e.Processors.Add(typeof(ExportPermissionRequest), new ExportPermissionRequestProcessor(permissionDictionary)); 21 }; 22 return security; 23 }; 24 // ... 25 }
初始化方法说明
1 WcfDataServerHelper.AddKnownType(typeof(ExportPermissionRequest));
在ExportController控制器中考虑自定义权限
自定义中,代码如下(不允许导出数据的用户禁用控制器):
1 public class SecuredExportController : ViewController { 2 protected override void OnActivated() { 3 base.OnActivated(); 4 ExportController controller = Frame.GetController<ExportController>(); 5 if (controller != null) { 6 controller.ExportAction.Executing += ExportAction_Executing; 7 if(SecuritySystem.Instance is IRequestSecurity) { 8 controller.Active.SetItemValue("Security", 9 SecuritySystem.IsGranted(new ExportPermissionRequest())); 10 } 11 } 12 } 13 void ExportAction_Executing(object sender, System.ComponentModel.CancelEventArgs e) { 14 SecuritySystem.Demand(new ExportPermissionRequest()); 15 } 16 }
添加演示数据
1 public class Updater : ModuleUpdater { 2 public Updater(IObjectSpace objectSpace, Version currentDBVersion) : 3 base(objectSpace, currentDBVersion) { } 4 public override void UpdateDatabaseAfterUpdateSchema() { 5 base.UpdateDatabaseAfterUpdateSchema(); 6 ExtendedSecurityRole defaultRole = CreateUserRole(); 7 ExtendedSecurityRole administratorRole = CreateAdministratorRole(); 8 ExtendedSecurityRole exporterRole = CreateExporterRole(); 9 Employee userAdmin = ObjectSpace.FindObject<Employee>(new BinaryOperator("UserName", "Admin")); 10 if (userAdmin == null) { 11 userAdmin = ObjectSpace.CreateObject<Employee>(); 12 userAdmin.UserName = "Admin"; 13 userAdmin.IsActive = true; 14 userAdmin.SetPassword(""); 15 userAdmin.Roles.Add(administratorRole); 16 } 17 Employee userSam = ObjectSpace.FindObject<Employee>(new BinaryOperator("UserName", "Sam")); 18 if (userSam == null) { 19 userSam = ObjectSpace.CreateObject<Employee>(); 20 userSam.UserName = "Sam"; 21 userSam.IsActive = true; 22 userSam.SetPassword(""); 23 userSam.Roles.Add(exporterRole); 24 userSam.Roles.Add(defaultRole); 25 } 26 Employee userJohn = ObjectSpace.FindObject<Employee>(new BinaryOperator("UserName", "John")); 27 if (userJohn == null) { 28 userJohn = ObjectSpace.CreateObject<Employee>(); 29 userJohn.UserName = "John"; 30 userJohn.IsActive = true; 31 userJohn.Roles.Add(defaultRole); 32 for (int i = 1; i <= 10; i++) { 33 string subject = string.Format("Task {0}",i); 34 Task task = ObjectSpace.FindObject<Task>(new BinaryOperator("Subject", subject)); 35 if (task == null) { 36 task = ObjectSpace.CreateObject<Task>(); 37 task.Subject = subject; 38 task.DueDate = DateTime.Today; 39 task.Save(); 40 userJohn.Tasks.Add(task); 41 } 42 } 43 } 44 ObjectSpace.CommitChanges(); 45 } 46 private ExtendedSecurityRole CreateAdministratorRole() { 47 ExtendedSecurityRole administratorRole = ObjectSpace.FindObject<ExtendedSecurityRole>( 48 new BinaryOperator("Name", SecurityStrategyComplex.AdministratorRoleName)); 49 if (administratorRole == null) { 50 administratorRole = ObjectSpace.CreateObject<ExtendedSecurityRole>(); 51 administratorRole.Name = SecurityStrategyComplex.AdministratorRoleName; 52 administratorRole.IsAdministrative = true; 53 } 54 return administratorRole; 55 } 56 private ExtendedSecurityRole CreateExporterRole() { 57 ExtendedSecurityRole exporterRole = ObjectSpace.FindObject<ExtendedSecurityRole>( 58 new BinaryOperator("Name", "Exporter")); 59 if (exporterRole == null) { 60 exporterRole = ObjectSpace.CreateObject<ExtendedSecurityRole>(); 61 exporterRole.Name = "Exporter"; 62 exporterRole.CanExport = true; 63 } 64 return exporterRole; 65 } 66 private ExtendedSecurityRole CreateUserRole() { 67 ExtendedSecurityRole userRole = ObjectSpace.FindObject<ExtendedSecurityRole>( 68 new BinaryOperator("Name", "Default")); 69 if (userRole == null) { 70 userRole = ObjectSpace.CreateObject<ExtendedSecurityRole>(); 71 userRole.Name = "Default"; 72 userRole.SetTypePermission<Task>(SecurityOperations.FullAccess, SecurityPermissionState.Allow); 73 userRole.SetTypePermission<Employee>(SecurityOperations.ReadOnlyAccess, SecurityPermissionState.Allow); 74 userRole.AddObjectPermission<PermissionPolicyUser>(SecurityOperations.ReadOnlyAccess, 75 "[Oid] = CurrentUserId()", SecurityPermissionState.Allow); 76 } 77 return userRole; 78 } 79 }
效果展示
运行WinForm或者ASP.NET,登录“Admin”用户,打开用户的详细视图。
登录“Sam”用户,“Export To”是可用的;登录“John”,“Export To”不是可用的。
参考网址
[2]完整项目演示:www.devexpress.com/example=E3794
[3] PermissionPolicyRole 的属性信息:https://documentation.devexpress.com/eXpressAppFramework/DevExpress.Persistent.BaseImpl.PermissionPolicy.PermissionPolicyRole.members
有志者,事竟成,破釜沉舟,百二秦关终属楚; 苦心人,天不负,卧薪尝胆,三千越甲可吞吴。