在很多业务场景中,我们需要携带token才能进行校验,这个token往往是前端放置在请求头里,传送到后端进行校验解析。下面使用拦截器+ThreadLocal方法对这些相同的逻辑进行统一处理。
1、编写UserThreadLocal
package com.tanhua.server.utils;
import com.tanhua.server.pojo.User;
//统一处理token
public class UserThreadLocal {
private static ThreadLocal<User>LOCAL=new ThreadLocal<>();
public UserThreadLocal(){
}
public static void set(User user){
LOCAL.set(user);
}
public static User get(){
return LOCAL.get();
}
}
2、编写TokenInterceptor
package com.tanhua.server.interceptor;
import com.tanhua.server.pojo.User;
import com.tanhua.server.service.UserService;
import com.tanhua.server.utils.NoAuthorization;
import com.tanhua.server.utils.UserThreadLocal;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 统一完成根据token查询用User的功能
*/
@Component //----------标记为组件,注册拦截器到Spring容器中
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService; //这个类是用于生产和解析token的
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
NoAuthorization noAnnotation = handlerMethod.getMethod().getAnnotation(NoAuthorization.class);
if (noAnnotation != null) {
// 如果该方法被标记为无需验证token,直接返回即可
return true;
}
}
//拦截toekn,解析后塞到UserThreadLocal里
String token = request.getHeader("Authorization");
if (StringUtils.isNotEmpty(token)) {
User user = this.userService.queryUserByToken(token);
if (null != user) {
UserThreadLocal.set(user); //将当前对象,存储到当前的线程中
return true;
}
}
//请求头中如不存在Authorization直接返回false
response.setStatus(401); //无权限访问
return false;
}
}
UserService 里的getUserByToken()方法如下
/**
* 根据token返回用户信息
* @param token
* @return
*/
public User getUserByToken(String token) {
Map<String, Object> body = null;
try {
// 通过token解析数据,获取token中paload里的用户id和过期时间
body = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
e.printStackTrace();}
Integer id = (Integer) body.get("id");
User user=new User();
user.setId(Long.valueOf(id));
return user;
}
3、编写注解NoAuthorization
有些是不需要检验token的,可以自定义一个这样的注解
package com.tanhua.server.utils;
import java.lang.annotation.*;
//该注解仅起标记作用
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented //标记注解
public @interface NoAuthorization {
}
4、注册拦截器
package com.tanhua.server.config;
import com.tanhua.server.interceptor.RedisCacheInterceptor;
import com.tanhua.server.interceptor.TokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(this.tokenInterceptor).addPathPatterns("/**");
}
}
5、使用ThreadLocal
User user=UserThreadLocal.get();