1.背景知识
1. ThreadLocal:ThreadLocal又称线程变量,该变量的作用范围为当前线程,具备线程隔离的特性。
2. 一次请求就是一个线程
2.实践
思路:拦截器进行拦截,如果没有token,则提示登录。有则获取用户数据并保存在ThreadLocal里。
2.1.配置拦截器
1@Component
public class LoginIntercept implements PathPatternInterceptor {
Logger logger = LoggerFactory.getLogger(LoginIntercept.class);
@Autowired
private List<LoginContextProvider> loginContextProviderList;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String accessToken = request.getHeader(ACCESS_TOKEN);
if(StringUtils.isEmpty(accessToken)){
logger.warn("accessToken为空,请重新登录");
ResponseUtil.out(response, ResponseUtil.resultMap(false, 401, "请重新登录"));
return false;
}
try {
Claims checkToken = JwtUtil.checkToken(accessToken, jwtProperties.getSecretKey());
if (checkToken != null) {
String subject = checkToken.getSubject();
String userInfo = stringRedisTemplate.opsForValue().get(subject);
// 登录已经失效
if (StringUtils.isEmpty(userInfo)) {
ResponseUtil.out(response, ResponseUtil.resultMap(false, 401, "请重新登录"));
return false;
}
User user = JSON.parseObject(userInfo, User.class);
UserContext.addUser(user);
return true;
}else{
ResponseUtil.out(response, ResponseUtil.resultMap(false, 401, "登录失效,请重新登录"));
return false;
}
}catch (Exception e){
logger.error("解析token异常",e);
ResponseUtil.out(response, ResponseUtil.resultMap(false, 401, "请重新登录"));
return false;
};
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserContext.clean();
}
}
2.2.配置ThreadLocal
public class UserContext {
private final static ThreadLocal<User> local = new ThreadLocal<User>();
public static void setUser(User user){
local.set(user);
}
public static User getUser(){
return local.get()
}
public static void clean(){
if(local.get() != null){
local.remove();
}
}
}