SpringCloud系列教程(十):token验证
上一节完成了gateway和微服务之间的token传递和验证,并且能正常获取到gateway解析出来的用户信息,看上去已经完成了,但是呢,如果我们微服务越来越多呢?难道每一个微服务都要添加一套解析功能吗?这样既浪费开发人员的时间,又无法保证所有人都能完成统一的验证功能,很可能最后变得项目验证方式五花八门,所以我们把token验证提取出来,单独作为一个项目,任何服务只要引入这个项目就能自动完成token验证的工作。
1、单独创建一个项目common,这个项目基本不怎么加SpringCloud的依赖,主要靠我们去写代码。
2、把之前写的TokenTool和JwtConfig两个文件复制到common项目里。
3、创建一个UserTool,用来保存userId信息,后续如果有其他的信息就可以继续丰富这个类了。
package com.mj.common.tool;
public class UserTool {
private static final ThreadLocal<String> tl = new ThreadLocal<>();
public static void addUserId(String userId) {
tl.set(userId);
}
public static String getUserId() {
return tl.get();
}
public static void removeUserId() {
tl.remove();
}
}
4、创建一个拦截器UserInterceptor,它的功能其实不是拦截,而是拦截之后取出userId,然后继续执行请求,并没有真正拦截的逻辑。
package com.mj.common.interceptor;
import cn.hutool.core.util.StrUtil;
import com.mj.common.tool.UserTool;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String userid = request.getHeader("userid");
if (StrUtil.isNotBlank(userid)) {
UserTool.addUserId(userid);
}
//全部放行,只是加了userId,并不执行拦截任务
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserTool.removeUserId();
}
}
我们真正的逻辑其实是把userId存起来,当请求完成时再把userId释放掉,每次请求都是一个独立线程,所以我们使用ThreadLocal来保存不同线程间的数据。
5、只有拦截器没什么用,因为这时候无法正常拦截请求,我们要把拦截器加入到服务中才行,所以我们再创建一个InterceptorConfig,把拦截器加进去。
package com.mj.common.config;
import com.mj.common.interceptor.UserInterceptor;
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 InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserInterceptor());
}
}
6、这样任何需要用common的module只要把它当做依赖引入项目里就可以了,我们把跟common重复的那些类文件删掉,这里注意,我们在nacos-client-demo项目里使用的JwtConfig文件本来是自动注入的,但是由于提取到了common中,就不会自动注入了,所以我们在nacos-client-demo的启动类上添加扫描的包名,从而把common中的也扫进去,gateway-demo不需要加,因为它不需要,所以common中的拦截器和config就被自动忽略。
package com.mj.nacosclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = "com.mj")
public class NacosClientDemoApplication {
public static void main(String[] args) {
SpringApplication.run(NacosClientDemoApplication.class, args);
}
}
7、这样项目就变成了这样一个清爽的样子。
8、重启服务,再测试一下吧,效果和上一节的一样,由于我们是对项目重构了,所以同学们要仔细修改。