假设有这么个需求,用户登录系统以后,将用户的token存入浏览器的本地存储,每次发送请求时将用户token携带上,方便后台控制层或业务层获取,那么此时可以有什么解决方案?
-
利用拦截器获取请求头中的token,然后将token存入请求域中,然后将这个request传入controller,controller再传给service,其实这里也不用再将token存入请求域,我们可以直接将这个request传入service,这样看起来也确实可以,但是假如业务方法很多,每个方法都需要token,难道还需要每个方法都要传递request对象?
-
利用拦截器获取请求头中token,将token存入ThreadLocal中,然后将这个ThreadLocal封装成一个工具类。这样在每个同步方法中都可以获取ThreadLocal中的值。只要是在一个线程里,就可以获取到。
拦截器类:
package com.example.appauth.interceptors;
import com.example.appauth.utils.ThreadLocalUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String s = UUID.randomUUID().toString();
System.out.println("interceptor:" + s);
ThreadLocalUtils.setToken(s);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//在方法执行完成移除token
ThreadLocalUtils.removeToken(s);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
utils工具类
package com.example.appauth.utils;
public class ThreadLocalUtils {
private static ThreadLocal<String> tokenThreadLocal = new ThreadLocal<>();
public static void setToken(String token){
tokenThreadLocal.set(token);
}
public static String getToken(){
return tokenThreadLocal.get();
}
public static void removeToken(){
if(tokenThreadLocal.get() != null){
tokenThreadLocal.remove()
}
}
}
controller
@GetMapping("tokentest")
public R tokentest(){
System.out.println("controller:" + ThreadLocalUtils.getToken());
userService.saveUser();
return R.success();
}
service
@Override
public void saveUser() {
String token = ThreadLocalUtils.getToken();
System.out.println("service:" + token);
}
启动访问测试
如果我们将service中的方法写在另一个线程中
@Override
public void saveUser() {
new Thread(()->{
String token = ThreadLocalUtils.getToken();
System.out.println("service:" + token);
}).start();
}
再测试
此时由于不在一个线程中,便无法获取。