@Component
public class UserTokenInterceptor implements HandlerInterceptor {
@Autowired
JwtTokenManagerProperties jwtTokenManagerProperties;
@Autowired
RedisTemplate<String, String> redisTemplate; //用户获取redis数据
//Spring路径匹配器AntPathMatcher
private AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1. 判断是否请求 controller中的方法 ,如果不是 直接放行
if (!(handler instanceof HandlerMethod)) {
return true;
}
//2. 从请求头中获取令牌 , Authorization
String token = request.getHeader("Authorization");
//3. 校验令牌是否为空 , 为空返回401
if (StrUtil.isEmpty(token)) {
//权限不足
throw new BaseException(BasicEnum.SECURITY_ACCESSDENIED_FAIL);
}
//4. 解析令牌, 并校验
Claims claims = JwtUtil.parseJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(), token);
//如果claims为空 , 则抛异常
if (claims == null) {
throw new BaseException(BasicEnum.SECURITY_ACCESSDENIED_FAIL);
}
//5. 获取用户数据 UserVo 返回object类型
String jsonStr = String.valueOf(claims.get("currentUser"));
//5.1 转为 UserVo
UserVo userVo = JSONUtil.toBean(jsonStr, UserVo.class);
//6. 取用户id 然后从redis中获取 该用户所能访问的 , 所有资源列表(包含按钮资源列表 和白名单列表)
Long userVoId = userVo.getId();
String urlStr = redisTemplate.opsForValue().get(CacheConstant.PUBLIC_ACCESS_URLS + userVo.getId());
//6.1 转为集合
List<String> urls = JSONUtil.toList(urlStr, String.class);
//7. 校验当前要访问的 资源 是否在用户所能访问的所有资源列表中
//7.1 获取当前要访问的资源路径 方法加路径
String target = request.getMethod() + request.getRequestURI();
//7.2 遍历集合和 当前要访问的资源路径 做比较
for (String url : urls) {
if (antPathMatcher.match(url, target)) {
//9. 如果在 将用户信息存入threadLocal 并放行
UserThreadLocal.setSubject(jsonStr);
return true;
}
}
//8. 如果不在 , 则说明没有权限访问该资源 返回403
throw new BaseException(BasicEnum.SECURITY_ACCESSDENIED_ERROR);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//清除threadLocal中的数据 防止内存泄漏
UserThreadLocal.removeSubject();
}
}
自定义拦截器
于 2024-07-12 15:40:55 首次发布