本文运行环境:jeeplus 2.6 等效于jeesite 1.2.7
还是我现在重做的项目管理系统(PM)的项目,遇到这样一个需求,除了传统的RBAC以外,对管理的项目Project还能够对其中的个别模块进行单独授权,比如某个人,没有管理项目的相应角色,但是针对某个项目,可以临时赋予其针对某个项目的角色,该角色拥有的权限只能在该项目生效。
目前公司里大致思路是全部抛开shiro的权限控制,自己写表来记录,写一个权限基类,再继承出子类,最后再在每个Controller里加@ModelAttribute拦截,在需要判断权限的模块的所有请求参数中附带上projectId,再去后台查找,如果没有权限抛出错误,在前台判断则用el表达式取变量值进行判断。在使用过程中,感觉到极其繁琐,于是业余琢磨别的方式。包括路径拦截,AOP等不一一赘述。经过查阅文档,发现shiro原生是可以支持的。 见参考文献中的5、实例级别的权限
在本项目中:匹配字符串为 模块:子模块:操作:实例ID(项目ID) ,其中前3段为原有权限,已定义在menu里
下面是实现过程:
- 授予角色的过程:新建一个表,起名为 prj_role_user ,其中包含 project_id ,role_id,user_id。每条记录代表在某个项目中,授予user某个角色。这里,为了节省开发成本,不单独写角色表,统一存放在原有角色表中,为了区分,我把角色的英文名前缀 改为project开头,建立角色时,只授予其单个项目的权限。
- 查找权限:通过关联查询,去menu中读取权限,权限字符串定义在里面
select project_id,user_id,permission FROM bd_prj_role_user as a join sys_role r on a.role_id =r.id join sys_role_menu rm on rm.role_id = r.id join sys_menu m on m.id = rm.menu_id join sys_user u on u.id = a.user_id WHERE r.del_flag='0' and m.del_flag='0' and u.del_flag='0' and r.useable='1' and permission!='' and user_id = ${userId}
- 拼接字符串并授权,将上述sql查询结果中的permission跟project_id拼接成字符串list,在SystemAuthorizingRealm中 找到覆盖的 doGetAuthorizationInfo方法,赋给SimpleAuthorizationInfo。
for (String permission : userProjectPermissionList) { info.addStringPermission(permission); }
- 调用方法:不能通过注解,因为无法引入projectId这个变量,改用
SecurityUtils.getSubject().checkPermission("basic:project:view:"+project.getId());
在前台调用时,可以在shiro标签内加el表达式拼接权限字符串。
参考资料 张开涛:《跟我学Shiro》第三章:授权
http://jinnianshilongnian.iteye.com/blog/2020017