- 由于restful风格接口路径中带有变量,使得权限控制成为一大难题,官方的各种权限框架比较复杂,一时间可能难以用的得心应手,给一些中小型项目转前后端分离带来一定的难度。
- 日常业务中,权限一般都需要能动态配置,本篇博客采用RBAC设计原则对系统的的权限进行设计。
- 核心思想是控制controller中方法的访问权限,将【类名】.【方法名】映射为一个资源,对该资源进行动态授权。
- 授权服务可以单独写一个项目作为授权中心(微服务),也可以集成到项目中(单体应用)。
- 用户登录时验证用户名密码是否正确,正确后验证token表中是否已经登录过,如果已经登录则直接返回之前的token,
生成token保存数据库,同时使用生成的token作为key在redis中缓存已登录用户的信息,
用户登出只需清除redis和数据库中的token信息即可,这样也可以在服务端强制下线某个用户。
表设计
用户表(sys_user):
字段名 | 数据类型 | 长度 | 必须 | 索引 | 备注 |
---|
id | bigint | – | 是 | primary key | 用户表主键 |
username | varchar | 255 | 是 | unique | 用户名,唯一索引 |
password | varchar | 255 | 是 | – | 密码编码后的密码 |
email | varchar | 255 | 是 | – | 邮箱 |
last_login | datetime | – | 否 | – | 最后登录时间 |
登录Token表(sys_token)
字段名 | 数据类型 | 长度 | 必须 | 索引 | 备注 |
---|
id | bigint | – | 是 | primary key | 主键 |
uid | bigint | – | 是 | unique | 登录用户id |
token | varchar | 255 | 是 | unique | token,唯一索引 |
refresh_token | varchar | 255 | 是 | unique | 刷新token(用户发出刷新请求时重置登录时间为当前时间) |
expiration | bigint | – | 是 | – | 有效时间(毫秒) |
login_time | datetime | – | 是 | – | 登录时间 |
角色组(sys_role_group):
字段名 | 数据类型 | 长度 | 必须 | 索引 | 备注 |
---|
id | bigint | – | 是 | primary key | 角色组表主键 |
user_group_name | varchar | 255 | 是 | – | 角色组名 |
角色表(sys_role):
字段名 | 数据类型 | 长度 | 必须 | 索引 | 备注 |
---|
id | bigint | – | 是 | primary key | 角色表主键 |
role_name | varchar | 255 | 是 | – | 角色名 |
rule_code | varchar | 255 | 是 | unique | 角色编码,唯一索引 |
group_id | bigint | – | 是 | – | 所属组 |
用户角和色组关联表(sys_user_role_group):
字段名 | 数据类型 | 长度 | 必须 | 索引 | 备注 |
---|
uid | bigint | – | 是 | index | 用户id |
gid | bigint | – | 是 | index | 组id |
用户角色关联表(sys_user_role):
字段名 | 数据类型 | 长度 | 必须 | 索引 | 备注 |
---|
uid | bigint | – | 是 | index | 用户id |
rid | bigint | – | 是 | index | 角色id |
接口权限表(sys_interface)
字段名 | 数据类型 | 长度 | 必须 | 索引 | 备注 |
---|
id | bigint | – | 是 | primary key | 主键id |
class_name | varchar | 255 | 是 | unique index | 包名+类名(考虑到不同系统类名可能重复) |
method_name | varchar | 255 | 是 | unique index | 方法名称 |
request_type | tinyint | – | 是 | unique index | 请求类型(1:get, 2:post,3:put,4:delete) |
接口权限角色关联表(sys_interface_role):
字段名 | 数据类型 | 长度 | 必须 | 索引 | 备注 |
---|
interface_id | bigint | – | 是 | index | 接口id |
rid | bigint | – | 是 | index | 角色id |
当然,不是很复杂的系统可以考虑不使用组设计,用户直接和角色关联
@Configuration
public class AuthorizaionInterceptor implements HandlerInterceptor {
@Value("${token.name:Authorization}")
private String tokenName;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
String token = request.getHeader(tokenName);
HandlerMethod h = (HandlerMethod) handler;
String methodName = h.getMethod().getName();
String className = h.getMethod().getDeclaringClass().getSimpleName();
System.out.printf("请求Controller ==》 %s.%s\n", className, methodName);
return true;
} else {
return true;
}
}
}
欢迎关注我的微信公众号,每天分享一点点,每天进步一点点
