源代碼GitHub:https://github.com/ZhaoRd/Zrd_0001_AuthorityManagementgit
對於權限管理系統來講,系統模塊是必須的一部分,那麼如何處理和收集模塊信息是一個管家步驟,在沒有看郭民峯的osharp以前,我能想到的都是經過管理員經過後臺管理進行管理,osharp裏採用attirbute的方式採集模塊信息。該demo借鑑osharp的方式,經過使用attribute定義模塊信息,程序啓動時經過判斷attribute進行模塊和具體功能權限的信息收集。github
對於新採集的信息,如何斷定這些新信息哪些是須要更新的,哪些是須要從已有信息中刪除的,哪些又是須要新增的呢?這裏須要使用到集合運算,具體請看如下內容。web
在web中,操做一個功能的訪問路徑是 controller/action ,在本demo中,一個controller就是一個功能,一個action就是一個具體的操做權限。在源代碼中,定義SystemModelAttribute來定義功能信息,代碼以下:數據庫
/// <summary> /// 收集系統模塊. /// </summary> public class SystemModelAttribute : Attribute { /// <summary> /// 模塊名稱. /// </summary> private string name; /// <summary> /// 分組名稱. /// </summary> private string groupName; /// <summary> /// 只讀模塊名稱. /// </summary> public string Name { get { return this.name; } } /// <summary> /// 分組名稱. /// </summary> public string GroupName { get { return this.groupName; } set { // 若是是經過構造函數初始化的名稱,則其餘設置均無效 if (string.IsNullOrEmpty(this.groupName)) { this.groupName = value; } } } /// <summary> /// 模塊的權限. /// </summary> private PermissionValue permissionValue; /// <summary> /// 模塊的權限. /// </summary> public PermissionValue PermissionValue { get { return this.permissionValue; } } /// <summary> /// Initializes a new instance of the <see cref="SystemModelAttribute"/> class. /// </summary> /// <param name="name"> /// 模塊名稱. /// </param> /// <param name="permissionValue"> /// 模塊權限值. /// </param> /// <param name="groupName"> /// 分組名稱. /// </param> public SystemModelAttribute(string name, PermissionValue permissionValue = PermissionValue.All, string groupName = null) { this.name = name; this.groupName = groupName; this.permissionValue = permissionValue; } }
在controller上使用該attribute,便可定義一個模塊,使用方式以下圖c#
SystemModelAttribute能夠定義須要採集的模塊信息,同理,能夠在定義一個attribute,來定義須要採集的權限信息,源代碼以下架構
/// <summary> /// 權限信息設置,以便信息收集. /// </summary> public class PermissionSettingAttribute : Attribute { /// <summary> /// 具體權限. /// </summary> private readonly PermissionValue permissionValue; /// <summary> /// Initializes a new instance of the <see cref="PermissionSettingAttribute"/> class. /// </summary> /// <param name="value"> /// The value. /// </param> public PermissionSettingAttribute(PermissionValue value) { this.permissionValue = value; } /// <summary> /// Gets the permission value. /// </summary> public PermissionValue PermissionValue { get { return this.permissionValue; } } }
使用方式以下:app
經過使用SystemModelAttribute和PermissionSettingAttribute來定義須要採集信息的內容.函數
咱們在Controller和Action上分別使用了不一樣的Attribute來定義信息,如何在代碼中收集這些信息呢?主要代碼以下ui
首先是獲取到Controller所在的程序集,而後根據得到的類型處理Type,具體的Invoke方法以下this
/// <summary> /// 解析Controller類型來收集Attribute信息. /// </summary> /// <param name="target"> /// The target. /// </param> /// <returns> /// The <see cref="IEnumerable"/>. /// </returns> public IEnumerable<FunctionDto> Invoke(Type target) { var result = new List<FunctionDto>(); var targetType = target; // 是否使用SystemModelAttribute if (!targetType.IsDefined(typeof(SystemModelAttribute), false)) { return result; } // 獲取全部Controller裏的方法 var methods = targetType.GetMethods(); // 獲取功能模塊的具體權限,必須是使用了PermissionSettingAttribute定義權限值,並取全部功能的並運算 // 例如:一個Controller裏只定義了Create和Edit,那麼這個功能模塊的權限就是 Create|Edit var functionPermissionValue = (from methodInfo in methods where methodInfo.IsDefined(typeof(PermissionSettingAttribute), false) select methodInfo.GetCustomAttribute<PermissionSettingAttribute>()).Aggregate( PermissionValue.None, (current, permissionSetting) => current | permissionSetting.PermissionValue); // 獲取SystemModelAttribute具體的信息 var description = targetType.GetCustomAttribute<SystemModelAttribute>(); var areaName = this.GetArea(target); var function = new FunctionDto() { FunctionName = description.Name, ModelName = areaName, PermissionValue = functionPermissionValue }; result.Add(function); return result; }
經過這樣的一個函數,就能夠採集到一個Controller裏的權限信息,一個功能就是一個Controller,Controller裏使用PermissionSettingAttribute定義的具體操做權限,全部定義的權限值取並運算,
如圖所示,一個Controller裏包含Create和Edit,那麼就說明這個功能模塊的最大權限是Create|Edit,這樣,在進行權限分配的時候,只能對該功能所具備的權限進行分配,未具備的權限不能分配.
通過上面的處理,那麼功能信息和權限信息都已經採集到了,將這些信息保存到數據庫,便可快捷方便的初始化系統的功能信息。
在信息處理方面,主要使用了集合運算,爲了對集合運算進行說明,我把已存在數據庫裏的功能信息集合定義爲 A集合,新採集的集合定義爲 B集合,那麼對於B集合而言,怎麼判斷哪些是須要新添加到數據庫,哪些是須要更新到數據庫的,已存在數據庫裏的功能,哪些又是須要刪除的呢?
a.對於須要添加的功能,能夠理解爲存在B集合可是不存在A集合
b.對於須要更新的功能,能夠理解爲即存在B集合又存在A集合
c.對於須要刪除的功能,能夠理解爲存在A集合中可是不存在B集合中
從集合的角度來處理a b c三種狀況,那麼
a. B集合 減 A集合
b. B集合 交 A集合
c. A集合 減 B集合
經過集合運算,就能夠獲得須要進行添加、更新、刪除的功能信息了
代碼以下:
/// <summary> /// 初始化系統功能. /// </summary> /// <param name="functionDtos"> /// The function dtos. /// </param> public void InitModel(IEnumerable<FunctionDto> functionDtos) { var functions = this.functionRepository.FindAll().ToList(); var addFunctions = functionDtos.Select(Mapper.Map<FunctionDto, Function>) .AsEnumerable(); // 建立如何判斷兩個function是否相等的條件 var functionComparer = EqualityHelper<Function>.CreateComparer(m => m.ModelName + "#" + m.FunctionName); var enumerable = addFunctions as Function[] ?? addFunctions.ToArray(); // 包含在將要處理的集合(addFunctions) // 但不包含在已經存在的集合(functions) // 表示須要添加到系統裏的模塊 // 差集運算 var toAddFunctions = enumerable.Except(functions, functionComparer); // 包含在已經存在的集合(functions) // 但不包含在將要處理的集合(addFunctions) // 表示須要從系統中刪除的模塊 // 差集運算 var toDeleteFunctions = functions.Except(enumerable, functionComparer); // 即包含在將要處理的集合(addFunctions) // 又包含在已經存在的集合(functions) // 表示須要更新內容 // 交集運算 var toUpdateFunctions = functions.Intersect(enumerable, functionComparer); LogHelper.Logger.Info( string.Format( "新增功能:{0}條;更新功能:{1}條;刪除功能:{2};", toAddFunctions.Count(), toUpdateFunctions.Count(), toDeleteFunctions.Count())); foreach (var addFunction in toAddFunctions) { addFunction.ID = Guid.NewGuid(); var role = this.roleRepository.Find( Specification<Role>.Eval(u => u.RoleName == "系統管理員")); this.functionRepository.Add(addFunction); // 初始化系統管理員的權限 this.functionInRoleRepository.Add(new FunctionInRole() { ID = GuidHelper.GenerateGuid(), Function = addFunction, PermissionValue = addFunction.PermissionValue, Role = role }); } foreach (var deleteFunction in toDeleteFunctions) { this.functionRepository.Remove(deleteFunction); } foreach (var updateFunction in toUpdateFunctions) { var function = updateFunction; var query = enumerable.Where(m => m.FunctionName == function.FunctionName); var newValue = string.IsNullOrEmpty(updateFunction.ModelName) ? query.SingleOrDefault(u => u.ModelName == null) : query.SingleOrDefault(u => u.ModelName == function.ModelName); if (newValue == null) { continue; } updateFunction.FunctionName = newValue.FunctionName; updateFunction.ActionName = newValue.ActionName; updateFunction.AreasName = newValue.AreasName; updateFunction.ControllerName = newValue.ControllerName; updateFunction.Description = newValue.Description; updateFunction.ModelName = newValue.ModelName; updateFunction.PermissionValue = newValue.PermissionValue; this.functionRepository.Update(updateFunction); } this.functionInRoleRepository.Context.Commit(); }
信息的定義和收集,主要是使用Attribute,該demo提供了一種使用Attribute的使用方式和方法。
該篇還提供了一個使用集合進行處理數據的方式,擴展了我再處理集合時的一些思路,之前老是經過for 循環來處理兩個集合,那麼經過集合運算,能夠很方便的獲得集合信息。
推薦QQ羣:
278252889(AngularJS中文社區)
5008599(MVC EF交流羣)
134710707(ABP架構設計交流羣 )
59557329(c#基地 )
230516560(.NET DDD基地 )
本人聯繫方式:QQ:351157970