基于角色的权限设计
这种方案是最常见也是比较简单的方案,不过通常有这种设计已经够了,这种方案对于每一个操作不做控制,只是在程序中根据角色对是否具有操作的权限进行控制
基于操作的权限设计
这种模式下每一个操作都在数据库中有记录,用户是否拥有该操作的权限也在数据库中有记录,结构如下:
基于角色和操作的权限设计
如上图所示,我们在添加了Role,和RoleAction表,这样子就可以减少UserAction中的记录,并且使设计更灵活一点。
但是这种方案在用户需求的考验之下也可能显得不够灵活够用,例如当用户要求临时给某位普通员工某操作权限时,我们就需要新增加一种新的用户角色,但是这种用户角色是不必要的,因为它只是一种临时的角色,如果添加一种角色还需要在收回此普通员工权限时删除此角色,我们需要设计一种更合适的结构来满足用户对权限设置的要求。
组合的权限设计
我们可以看到在上图中添加了UserAction表,使用此表来添加特殊用户的权限,改表中有一个字段HasPermission可以决定用户是否有某种操作的权限,改表中记录的权限的优先级要高于UserRole中记录的用户权限。这样在应用程序中我们就需要通过UserRole和UserAction两张表中的记录判断权限。
有可能用户还会给出这样的需求:对于某一种action所操作的对象某一些记录会有权限,而对于其他的记录没有权限,比如说一个内容管理系统,对于某一些频道某个用户有修改的权限,而对于另外一些频道没有修改的权限,这时候我们需要设计更复杂的权限机制。
对于同一种实体(资源)用户可以对一部分记录有权限,而对于另外一些记录没有权限的权限设计
对于这样的需求我们就需要对每一种不同的资源创建一张权限表,在上图中对Content和Channel两种资源分别创建了UserActionContent和UserActionChannel表用来定义用户对某条记录是否有权限;这种设计是可以满足用户需求的但是不是很经济,UserActionChannel和UserActionContent中的记录会很多,而在实际的应用中并非需要记录所有的记录的权限信息,有时候可能只是一种规则,比如说对于根Channel什么级别的人有权限;这时候呢我们就可以定义些规则来判断用户权限,下面就是这种设计。
涉及资源,权限和规则的权限设计
#region 过滤登录用户的菜单权限
/// <summary>
/// 1: 可以按照用户---角色---权限这条线找出登录用户的权限,放在一个集合中。
/// 2:可以按照用户---权限这条线找出用户的权限,放在一个集合中。
/// 3:将这两个集合合并成一个集合。
/// 4:把禁止的权限从总的集合中清除。
/// 5:将总的集合中的重复权限清除。
/// 6:把过滤好的菜单权限生成JSON返回。
/// </summary>
/// <returns></returns>
public ActionResult Getmenus()
{
//1: 可以按照用户---角色---权限这条线找出登录用户的权限,放在一个集合中。
//获取登录用户的信息
var userInfo = UserInfoService.Load(u => u.Id == LoginUser.Id).FirstOrDefault();
//获取登录用户的角色.
var userRoleInfo = userInfo.RoleInfo;
//根据登录用户的角色获取对应的菜单权限。
short actionTypeEnum = (short)ActionTypeEnum.MenumActionType;
var loginUserMenuActions = (from r in userRoleInfo
from a in r.ActionInfo
where a.ActionTypeEnum == actionTypeEnum
select a).ToList();
//下面语句是错误的,allUserActions是一个大集合该集合中包含了很多小的集合,所以变量b为集合类型
//var allUserActions = from r in userRoleInfo
// select r.ActionInfo;
//var mm = from b in allUserActions
// where b.ActionTypeEnum == actionTypeEnum
// select b;
// 2:可以按照用户---权限这条线找出用户的权限,放在一个集合中。
var userActions = from a in userInfo.R_UserInfo_ActionInfo
select a.ActionInfo;
var userMenuActions = (from a in userActions
where a.ActionTypeEnum == actionTypeEnum
select a).ToList();
// a.ActionInfo不是一个集合,注意理解权限表与用户权限关系表之间的对应关系
//var userMenuActionse = from a in userInfo.R_UserInfo_ActionInfo
// from b in a.ActionInfo
// where b.ActionTypeEnum == actionTypeEnum
// select b;
//3:将这两个集合合并成一个集合。
loginUserMenuActions.AddRange(userMenuActions);
//4:把禁止的权限从总的集合中清除。
var forbidActions = (from a in userInfo.R_UserInfo_ActionInfo
where a.IsPass == false
select a.ActionInfoID).ToList();
var loginUserAllowActions = loginUserMenuActions.Where(a => !forbidActions.Contains(a.Id));
//5:将总的集合中的重复权限清除。
var lastLoginUserActions = loginUserAllowActions.Distinct(new EqualityComparer());
//6:把过滤好的菜单权限生成JSON返回。
var temp = from a in lastLoginUserActions
select new { icon = a.MenuIcon, title = a.ActionInfoName, url = a.Url };
return Json(temp, JsonRequestBehavior.AllowGet);
}
#endregion