【项目】升级现有的授权系统

现有的授权系统已无法满足对业务的支持,所以有必要针对授权系统进行一次升级。在升级之前先详细拆解一下之前的授权系统。

旧的授权系统

详情

认证系统负责颁发令牌,系统一共拥有3种类型的用户,分别是普通用户、系统用户和微服务。其中普通用户和系统用户都是共用的同一种类型的token,叫做UserToken,微服务使用的是ClientToken。这两种不同类型的token在传输过程中使用不同的请求头进行存储,当微服务之间互相调用的时候,会有一个feign拦截器负责把当前线程中的用户token和本身的微服务token,存入到对应的请求头中。发送mq时,也是采用了类似的机制进行传递token。尤其要注意的是在只有微服务token时并且CheckUserToken注解不为空时,拦截器会把微服务的信息转换成用户信息存储到安全上下文中,但不会设置用户token

流程图

img

旧系统的痛点

  • 无法做到针对每个接口进行访问控制
  • 没有token续期功能,用户体验不好
  • 没有能力提供给外部系统与我们进行对接

新的授权系统

对每个接口进行访问控制

授权过程

在实际的授权过程中,可以在请求到达接口之前,使用拦截器来进行身份验证和授权处理。在拦截器中,首先从请求头中获取Token,如果Token不存在,则返回“未授权”的错误信息。

如果Token存在,则使用JWTToken进行解密和验证,如果解密和验证成功,则从Token中获取用户信息和访问权限信息,并将它们存储在ThreadLocal中,以便在整个请求处理过程中可以方便地访问它们。

最后,在请求处理完成后,清除ThreadLocal中存储的信息,以避免对下一个请求产生干扰。

流程图

img

Token续期

Token刷新机制

JWT Token自动刷新机制需要在前端和后端同时实现。

在每次请求的返回中都检查 token 是否快过期,如果临近过期就刷新 token,并且在 response 的 header 中返回给前端。前端可以通过读取响应 header 中的 token 来更新本地的 token。

具体实现可以在后端的拦截器中添加一个逻辑,在每次请求返回时检查 token 是否快过期,如果是,则进行 token 的刷新。同时,将新的 token 放入 response 的 header 中返回给前端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 伪代码
public class TokenRefreshInterceptor implements HandlerInterceptor {

private TokenProvider tokenProvider;

public TokenRefreshInterceptor(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 检查 token 是否需要刷新
String token = tokenProvider.resolveToken(request);
if (token != null && tokenProvider.isTokenNeedRefresh(token)) {
// 刷新 token
String newToken = tokenProvider.refreshToken(token);
// 将新的 token 放入响应 header 中
response.setHeader("Authorization", "Bearer " + newToken);
}
}
}
流程图

imgc