java后台快速开发框架若依的权限系统使用起来其实非常简单。若依的权限管理分成两个部分:权限标识和数据权限。
权限标识(权限字符串)
首先先来讲用权限字符串实现的RBAC权限管理系统。想必用若依的肯定看到“content:article:list”这种形式的字符串放在控制器方法头上。这个就是权限字符串。用户拥有的权限字符串就相当于钥匙,要执行的方法就是要开的锁。你只有拥有钥匙才能开锁。
当我们新增一个用户时,新用户是没用任何权限的,我们要先赋予这个新用户角色。而角色就相当于钥匙串,如果你没往上面挂钥匙那么你就没有任何权限。
菜单管理界面列出了访问菜单所需要的权限标识(权限字符串),你登录的用户所拥有的角色如果没有这些权限就看不到这些菜单。
创建角色的时候有个树状列表让你选这些菜单,就是往钥匙串上挂钥匙的过程。这些菜单上有哪些权限标识,就会往这个角色上赋予哪些权限标识。
创建完角色,赋予了角色权限,然后再将角色赋予新创建的用户,这样授权就完成了。但是如果授权之前用户处于在线状态,授权后用户没有退出重新登陆,直接刷新浏览器的话是仍然没有权限的。原因很简单,管理员修改完权限,数据库内的数据更新了,而新用户存储再redis上的登录信息没有更新,就依然没有权限。我们打开redis,看一下redis内存储的登录信息:
发现在permissions字段内,存储了用户拥有的所有权限标识(权限字符串)。
可以看出,授权逻辑是这样的:
-
创建角色,赋予这个角色权限
-
将这个角色赋予用户,用户则拥有了这个角色所拥有的所有权限
这些信息都存在mysql这类的数据库里。
而鉴权逻辑是这样的:
-
用户登录的时候系统查询数据库,将用户拥有的所有权限以权限字符串的形式发给用户,也就是作为登录信息(session)存到redis里。
-
在用户进行需要权限的操作时,系统会取出redis中用户的登录信息,从中得到权限字符串,再将操作需要的权限字符串拿去和用户拥有的权限字符串进行比对,如果找不到需要的权限字符串,则判定为没有权限。找到了就鉴权成功。
通过这种方法,可以实现对页面和页面上任意一个组件的权限控制。比如一个页面上的一个按钮需要aaa:bbb:ccc权限,用户有这个权限字符串则显示,没有则不显示。vue版前端项目实现组件鉴权的方法是v-hasPermi="['aaa:bbb:ccc']"。
管理员拥有的权限是“*:*:*”,就相当于一把万能钥匙,能开所有的锁,拥有任何操作的权限。
数据权限
数据权限解决的是一个很常见的需求:一个博客网站,很多作者都能在网站上发布文章。博客的后台每个作者只能看到和操作自己的文章,看不到别人发布的。
若依解决这个需求的方式是这样:首先给角色设定是否启用数据权限。多个角色中生效范围最小的
然后在控制器层接收一个继承了若依框架提供的BaseEntity的entity,这个entity上携带了sql语句,然后将这个对象传递给mybatis的mapper,让mybatis自动拼接出where user_id=...这样的sql语句,这样就实现了根据当前用户id进行查询。
以之前提到的的博客网站为例,首先先创建一个继承了BaseEntity的类Article。然后在控制器的方法头顶上标出注解“@DataScope()”
注意,如果有用联表查询则需要写出mapper xml中sql语句里 sys_user表的别名。我用的别名是“u”,所以应该写成@DataScope(userAlias = "u") 。如果是联部门表sys_dept的话则为deptAlias = "..."
然后在控制器方法的参数中写上类,也就是Article类。(如上图所示)
这样在执行到这个方法时,若依框架会根据当前用户,往article类上挂上sql语句。
确保xml文件中sql语句的 <where>标签内添加了${params.dataScope},parameterType写上类名
接下来将这个类传递给mybatis的mapper,就大功告成了。
再来整理一下数据权限的使用流程:
-
角色配置数据权限
-
entity继承BaseEntity
-
控制器添加@DataScope注解,方法参数传递entity
-
将entity传递给mapper
-
mapper内的sql末尾添加${params.dataScope}
这样我们就实现了根据当前登录用户过滤数据的数据权限功能。