统一处理token
拦截器
拦截器( Interceptor)是一种动态拦截方法调用的机制
拦截器和过滤器的区别
1、处理token的逻辑代码
@Service
public class UserService {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);
@Autowired
private RedisTemplate<String, String> redisTemplate;
public User getUserByToken(String token) {
String redisUserValue = redisTemplate.opsForValue().get(token);
if (StringUtils.isNotEmpty(redisUserValue)) {
// 说明用户是登录状态
try {
// 刷新 token的存储时间
redisTemplate.expire(token, 1, TimeUnit.HOURS);
return OBJECT_MAPPER.readValue(redisUserValue, User.class);
} catch (IOException e) {
LOGGER.error("解析token发生异常", e);
}
}
// 用户未登录
return null;
}
}
2、自定义一个方法注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Authorization {
}
// 用来标记需要Authorization(授权) 的方法
3、编写TokenInterceptor 拦截器
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 只需要拦截带有token的请求
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Authorization annotation = handlerMethod.getMethod().getAnnotation(Authorization.class);
if (annotation == null) {
// 请求方法上没有该注解的话,说明该方法没有携带token值,直接放行即可
return true;
}
}
// 有注解的情况 token 能解析出来的情况
String token = request.getHeader("Authorization");
if (StringUtils.isNotEmpty(token)) {
User user = userService.getUserByToken(token);
if (null != user) {
UserThreadLocal.set(user);
// 放行即可
return true;
}
}
// token解析异常的情况
response.setStatus(444);
return false;
}
}
4、UserThreadLocal
public class UserThreadLocal {
private static final ThreadLocal<User> LOCAL = new ThreadLocal<User>();
private UserThreadLocal() {
}
public static void set(User user) {
LOCAL.set(user);
}
public static User get() {
return LOCAL.get();
}
/**
* 防止内存泄漏
*/
public static void remove(){
LOCAL.remove();
}
}
5、注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
}
}
使用的时候,请求方法上面本来携带token的参数,就可以用注解@Authorization 代替,入参就可以不用编写了
ThreadLocal ???