restful接口权限控制及其灵活授权

  • 由于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 {

	// 配置文件中配置的请求头中获取token的名称,默认为:Authorization
 	@Value("${token.name:Authorization}")
    private String tokenName;

	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws 	Exception {
    	// 判断是否请求的controller中的请求
        if (handler instanceof HandlerMethod) {
        	// 获取token
            String token = request.getHeader(tokenName);
        	// 强制类型转换
            HandlerMethod h = (HandlerMethod) handler;
            // 获取请求的方法名称
            String methodName = h.getMethod().getName();
            // 获取请求的Controller类全名称(包名+类名)
            String className = h.getMethod().getDeclaringClass().getSimpleName();
            // 在这进行数据库或redis缓存验证登录用户是否具有访问权限
            /*
            	登录时对用户所拥有的权限生成一个对象保存到redis中,key为token
            	在此处进行校验时直接从redis中取对象,如果取不到去数据库中根据token查询是否登录,
            	如果没查到则为无效token
            	如果查到则进行过期判断,如果过期则无效
            	如果合法则判断是否拥有权限
            	有则通过,没有则response返回401提示没有权限
            */
            System.out.printf("请求Controller ==》 %s.%s\n", className, methodName);
            return true;
        } else {
            return true;
        }
    }
}

欢迎关注我的微信公众号,每天分享一点点,每天进步一点点
阿里桃子的技术栈

猜你喜欢

转载自blog.csdn.net/csdn_meng/article/details/91967882