- 由于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;
}
}
}
欢迎关注我的微信公众号,每天分享一点点,每天进步一点点