我们发现 每一个控制方法中都需要解析token , 获取当前用户id , 代码重复度比较高
也就是每次请求都会获取解析token 很麻烦
基于ThreadLocal + 拦截器的形式统一处理
拦截器
是一种动态拦截方法调用的机制;
类似于Servlet 开发中的过滤器Filter,用于对处理器进行前置处理和后置处理。
threadlocal
线程内部的存储类,赋予了线程存储数据的能力。
线程内调用的方法都可以从ThreadLocal中获取同一个对象。
多个线程中ThreadLocal数据相互隔离
Threadlocal使用方法很简单
ThreadLocal<T> threadLocal = new ThreadLocal<T>();
threadLocal.set() //将数据绑定到当前线程
threadLocal.get() //从当前线程中获取数据
Thread工具类
import com.tanhua.domain.User;
/**
* Created with IntelliJ IDEA.
*
* @Author:
* @Date:
* @Message: Talk is cheap. Show me the code.
* @Description:
*/
public class UserHolder {
private static ThreadLocal<User> t1 = new ThreadLocal<>();
// 设置
public static void set(User user) {
t1.set(user);
}
// 获取
public static User get() {
return t1.get();
}
// 删除
public static void remove() {
t1.remove();
}
// 获取用户id
public static Long getUserId() {
if (t1.get() != null) {
return t1.get().getId();
}
return null;
}
// 获取用户手机号
public static String getUserMobile() {
if (t1.get() != null) {
return t1.get().getMobile();
}
return null;
}
}
定义拦截器,在前置拦截方法preHandle中解析token并验证有效性,如果失效返回状态码401。如果有效,解析User对象,存入ThreadLocal中
import cn.hutool.core.util.StrUtil;
import com.tanhua.JWTUtil;
import com.tanhua.domain.User;
import io.jsonwebtoken.Claims;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created with IntelliJ IDEA.
*
* @Author:
* @Date:
* @Message: Talk is cheap. Show me the code.
* @Description:
*/
public class TokenIterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取token
String token = request.getHeader("Authorization");
// 验证token
if (StrUtil.isBlank(token)) {
return false;
}
// 解析token
Claims claims = JWTUtil.parseToken(token, "tanhua");
// 验证token里面的键值
if (claims == null) {
return false;
}
// 构造user 对象 存入UserHolder
User user = new User();
user.setId(Long.valueOf(claims.get("userId").toString()));
user.setMobile(claims.get("mobile").toString());
UserHolder.set(user);
return true;
}
}
拦截器需要注册到MVC容器中 使用 @Configuration 注解实现
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Created with IntelliJ IDEA.
*
* @Author:
* @Date:
* @Message: Talk is cheap. Show me the code.
* @Description:
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* @Description: 添加拦截器
* @Param: [registry]
* @return: void
* @Author:
* @Date:
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器 TokenIterceptor
registry.addInterceptor(new TokenIterceptor())
.addPathPatterns(("/**"))
.excludePathPatterns("/user/login","/user/loginVerification");
}
}
然后 使用的时候也很简单 只需要
Long userId = UserHolder.getUserId();