网关登陆校验
2026年3月11日大约 5 分钟
网关登陆校验
整体思路:
- 用户访问网关,携带token
- 网关接收到请求后,提取token并进行校验
- 如果校验通过,允许请求继续路由到目标服务;如果校验失败,直接返回错误响应给用户

图:网关登陆校验流程
自定义过滤器
在SpringCloudGateway中,提供了两种类型的过滤器:
- GatewayFilter:全局过滤器,作用于任意指定的路由规则。
- GlobalFilter:全局过滤器,作用于所有路由规则。
自定义GlobalFilter
- 实现GlobalFilter接口,重写filter方法,在其中编写校验逻辑
- 如果需要指定过滤器的执行顺序,可以实现Ordered接口,重写getOrder方法,返回一个整数值,值越小优先级越高。
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest(); // 获取请求对象
log.info("MyFilter 执行");
return chain.filter(exchange); // 放行,继续执行后续的过滤器和路由逻辑
}
@Override
public int getOrder() {
return 0; // 设置过滤器的优先级,值越小优先执行
}
}ServerWebExchange exchange:封装了HTTP请求和响应的上下文对象,可以通过它获取请求信息、设置响应信息等。GatewayFilterChain chain:过滤器链对象,调用它的filter方法可以继续执行后续的过滤器和路由逻辑。Mono<Void>:表示一个异步操作,完成时没有返回值。在过滤器中,通常需要返回一个Mono<Void>对象来表示过滤器的执行结果。
实现登陆校验
使用到的方法或对象
exchange.getRequest():获取HTTP请求对象,可以从中提取请求头、请求参数等信息。chain.filter(exchange):放行,继续执行后续的过滤器和路由逻辑AntPathMatcher:Spring提供的路径匹配工具类,可以用来判断请求路径是否符合某个模式,例如是否在放行列表中。
校验逻辑
- 获取请求头
- 判断是否请求路径是否放行
- 从请求头中进行非空校验,并提取token
- 调用Jwt工具类进行token校验
- 如果校验失败,直接返回错误响应;如果校验通过,放行
@Component
public class AuthGlobalFilter implements GlobalFilter , Ordered {
@Resource
private AuthProperties authProperties;
@Resource
private JwtTool jwtTool;
private final AntPathMatcher pathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取Request
ServerHttpRequest request = exchange.getRequest();
// 2. 判断是否拦截
if(isExclude(request.getPath().toString())){
return chain.filter(exchange); // 放行
}
// 3.获取token
String token = null;
List<String> headers = request.getHeaders().get("authorization");
if(headers != null && !headers.isEmpty()){
token = headers.get(0);
}
// 校验并且解析token
Long userId = null;
try{
userId = jwtTool.parseToken(token);
} catch (UnauthorizedException e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// TODO 传递用户信息
System.out.println("userId = " + userId);
return chain.filter(exchange);
}
/*
* 判断是否为放行路径
* */
private boolean isExclude(String string) {
for (String path : authProperties.getExcludePaths()) {
if (pathMatcher.match(path, string)) {
return true;
}
}
return false;
}
@Override
public int getOrder() {
return 0;
}
}用户信息传递

图:网关用户信息传递流程
使用的方法或对象
ServerWebExchange exchange:封装了HTTP请求和响应的上下文对象,可以通过它获取请求信息、设置响应信息等。exchange.getRequest().mutate():获取请求对象的设置器,可以用来修改请求信息,例如添加请求头等。chain.filter(exchange):放行,继续执行后续的过滤器和路由逻辑HttpServletRequest request:在目标服务中,可以通过HttpServletRequest对象获取请求信息,例如请求头、请求参数等。request.getHeader("userId"):获取请求头中的用户ID信息。
传递用户信息的逻辑
- 在网关过滤器中,校验token并解析出用户ID
- 将用户ID添加到请求头中,继续放行
String userId = jwtTool.parseToken(token); // 将用户ID添加到请求头中 exchange.mutate().request(request -> request.header("userId", userId)).build(); return chain.filter(exchange); // 放行,继续执行后续的过滤器和路由逻辑 - 在通用模块中,创建拦截器类,获取请求头中的用户ID,并将其存储在ThreadLocal中
注意
需要
UserContext类来封装ThreadLocal,提供设置、获取和清除用户ID的方法public class UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String userId = request.getHeader("userId"); if (userId != null) { UserContext.setUserId(Long.valueOf(userId)); } return true; // 继续执行后续的处理器 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserContext.removeUser(); // 请求处理完成后,清除ThreadLocal中的用户信息 } } - 在
MvcConfig类中注册拦截器注意
如果只在特定模块中使用拦截器,可以使用
@ConditionalOnClass注解来控制拦截器的注册要求@Configuration @ConditionalOnClass(DispatcherServlet.class) // 只有当DispatcherServlet类存在时才注册该配置类 public class MvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new UserInterceptor()) } }
OpenFeign传递用户信息-服务间传递
在使用OpenFeign进行服务间调用时,也需要将用户信息传递到目标服务中。
可以通过Feign的RequestInterceptor拦截器来实现这一功能。
- 创建一个
RequestInterceptor的Bean,在其中获取ThreadLocal中的用户ID,并将其添加到Feign请求的头部public class DefaultFeignConfig { @Bean public RequestInterceptor userInfoRequestInterceptor() { return new RequestInterceptor() { @Override public void apply(RequestTemplate template) { Long userId = UserContext.getUser(); if (userId != null) { template.header("user-info", userId.toString()); } } }; } } - 在目标服务中,启动类上添加
@EnableFeignClients注解,并指定Feign配置类@SpringBootApplication @EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class) public class TargetServiceApplication { public static void main(String[] args) { SpringApplication.run(TargetServiceApplication.class, args); } }