源代码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