访问控制层、逻辑层或者数据层,都可能需要获取请求头里的Authorization,解析token,得到比如用户id或者username,这样每次都需要用md5来解析,代码重复,不优雅。
其实我们已经在拦截器中获取到了token,如下:
所以,我们只需要在拦截器内,将token的解析结果claims放到ThreadLocal这个全局变量中,线程具有隔离作用,每个新的请求,内部会开出新的线程,保证token始终和ThreadLoal绑定在一起。
逻辑如下:
用ThreadLocal将claims存起来,全局变量,后面用到,则取。
代码如下:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//方法内部,需要拦截,拦截下来,需要验证,验证通过则放行
//令牌验证
String token = request.getHeader("Authorization");
//验证token,取协议头的Authorization,如果验证不报异常,则返回数据,报异常,则返回401,401需要response
try{
//1.这里已经获取到了token,并将token解析放到了claims的map集合中
Map<String, Object> claims = JwtUtil.parseToken(token);
//2.将claims用ThreadLocal存起来,后面每次加载,都在一个线程内获取到同样的claims
ThreadLocalUtil.set(claims);
//放行
return true;
}catch (Exception e){
response.setStatus(401);
//拦截
return false;
}
}
每次请求后,清除ThreadLocal,防止内存溢出。
在controller层,访问userInfo不再需要获取token,而是直接获取ThreadLoacl的claims:
用apifox访问,正常:
最后,附上ThreadLocalUtils工具类:
package com.aibaodian.baymaxexpress.utils;
import java.util.HashMap;
import java.util.Map;
/**
* ThreadLocal 工具类
*/
@SuppressWarnings("all")
public class ThreadLocalUtil {
//提供ThreadLocal对象,
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
//根据键获取值
public static <T> T get(){
return (T) THREAD_LOCAL.get();
}
//存储键值对
public static void set(Object value){
THREAD_LOCAL.set(value);
}
//清除ThreadLocal 防止内存泄漏
public static void remove(){
THREAD_LOCAL.remove();
}
}