AOP的特性使得它非常適合用來設計類似權限控制的功能,這是本文的基礎,如果想要了解AOP的實現,可以參考《動態織入的AOP實現》。
在基於角色的訪問控制(RBAC)中,有三要素:用戶、角色、任務(或操作)(User、Role、Task),其穩定性逐漸增強,兩個關系,User<->Role、Role<->Task,其中:
- User 是日常管理運行時建立
- Role 是部署/交付建立
- Task 是開發時確定
- User<->Role 是日常管理運行時建立
- Role<->Task 是部署/交付時建立
在本例中,針對Task和Role,我們設計如下的兩個類:
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class TaskAttribute: Attribute { public TaskAttribute(string taskName, string taskDescription) { TaskName = taskName; TaskDescription = taskDescription; } public string TaskName { get; set; } public string TaskDescription { get; set; } } public class Role { public string Name { get; set; } public List<TaskAttribute> Tasks { get; set; } }
可以看到,Task是繼承自Attribute的,源於Task需要和實際的功能接口匹配起來,而Role,則無此需要。
本文演示所需要的權限關系描述如下:
1:系統有4個權限;
2:系統有兩個角色,一個叫做Manager,它具有兩個權限,另一個角色為Common,它當前不具備任何權限;
以上的關系描述,我們在代碼當中模擬如下:
//模擬系統總共有4種權限 public static List<TaskAttribute> Tasks { get { if (_tasks == null) { _tasks = new List<TaskAttribute>() { new TaskAttribute("AddItem","增加"), new TaskAttribute("ModifyItem","修改"), new TaskAttribute("RemoveItem","刪除"), new TaskAttribute("ListItem","獲取列表") }; } return _tasks; } } private static List<Role> _roles; //模擬系統總共有兩類角色 //第一類角色Manager,有增加和修改權限 //第二類角色Common,沒有任何權限 public static List<Role> Roles { get { if (_roles == null) { _roles = new List<Role>() { new Role(){Name = "Manager", Tasks = new List<TaskAttribute>() { new TaskAttribute("AddItem","增加"), new TaskAttribute("ModifyItem","修改") }}, new Role(){Name = "Common", Tasks = new List<TaskAttribute>()} }; } return _roles; } }
權限判斷在切面部分,簡化如下(可以看到是判斷當前用戶是否具有相關權限):
public class AuthorityHandler : ICallHandler { /// <summary> /// Invoke order /// </summary> public int Order { get; set; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { MethodBase mb = input.MethodBase; object[] attrObj = mb.GetCustomAttributes(typeof(TaskAttribute), false); if (attrObj == null) { throw new ArgumentException("TaskAttribute should be defined with the AuthorityAttribute"); } else { TaskAttribute attr = (TaskAttribute)attrObj[0]; if (!string.IsNullOrEmpty(attr.TaskName)) { string taskName = attr.TaskName; //get current user's roles IEnumerable<Role> currentUserRoles = from p in SampleApp.Roles where p.Name == SampleApp.User.Name select p; //if match then return; foreach (Role currentUserRole in currentUserRoles) { IEnumerable<TaskAttribute> tasks = from p in currentUserRole.Tasks where p.TaskName == taskName select p; if (tasks.Count() > 0) { var retvalue = getNext()(input, getNext); return retvalue; } } //else throw exception throw new UnauthorizedAccessException("access denied"); } } return null; } } public class AuthorityAttribute : HandlerAttribute { public override ICallHandler CreateHandler(IUnityContainer container) { return new AuthorityHandler(); } }
調用方代碼:
static void Main() { var container1 = new UnityContainer() .AddNewExtension<Interception>() .RegisterType<IBiz, Biz1>(); container1 .Configure<Interception>() .SetInterceptorFor<IBiz>(new InterfaceInterceptor()); SampleApp.User = new User() { Name = "Common" }; var sample1 = container1.Resolve<IBiz>(); sample1.AddItem(); Console.ReadKey(); }
可以看到,使用了Unity來進行AOP;
運行效果:
代碼下載:權限.rar