Spring Cloud Gateway 实现统一鉴权最标准的做法是实现 GlobalFilter 接口,将其注册为 Bean 后即可对所有路由生效。
先说结论:通过实现 GlobalFilter 接口并在 filter 方法中拦截请求,适合网关层统一校验 Token 或签名。
- 适合全局限权场景
- 需注意 Filter 执行顺序
- 严禁阻塞操作
- 需处理 OPTIONS 跨域请求
前置依赖
确保项目中包含 Spring Cloud Gateway 起步依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>完整代码实现
以下代码包含白名单放行、OPTIONS 请求处理、Token 校验及 JSON 错误响应写入,可直接参考使用。
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
// 白名单路径,无需鉴权
private static final List<String> WHITE_LIST = Arrays.asList(
"/auth/login", "/actuator/health"
);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().value();
String method = request.getMethod().name();
// 1. 放行白名单路径
if (WHITE_LIST.stream().anyMatch(path::startsWith)) {
return chain.filter(exchange);
}
// 2. 放行跨域预检请求
if ("OPTIONS".equalsIgnoreCase(method)) {
return chain.filter(exchange);
}
// 3. 获取 Token
String token = request.getHeaders().getFirst("Authorization");
// 4. 校验逻辑 (此处替换为实际 JWT 校验)
if (token == null || !token.startsWith("Bearer ")) {
return unauthorized(exchange);
}
// 5. 鉴权通过,继续链路
return chain.filter(exchange);
}
// 统一返回 401 JSON 错误
private Mono<Void> unauthorized(ServerWebExchange exchange) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
String body = "{\"code\":401,\"msg\":\"Unauthorized\"}";
DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();
DataBuffer dataBuffer = bufferFactory.wrap(body.getBytes(StandardCharsets.UTF_8));
return exchange.getResponse().writeWith(Mono.just(dataBuffer));
}
@Override
public int getOrder() {
// 优先级高于一般业务过滤器
return -100;
}
}验证方法
1. 无 Token 请求测试
使用 curl 命令访问受保护接口,不带 Authorization 头,预期返回 401 状态码及 JSON body。
curl -i http://gateway-host/api/protected2. 有 Token 请求测试
带上合法的 Token 请求,预期返回 200 状态码或后端服务的实际响应。
curl -i -H "Authorization: Bearer valid_token" http://gateway-host/api/protected3. 跨域请求测试
发送 OPTIONS 请求,预期直接放行返回 200,不被鉴权拦截。
curl -i -X OPTIONS http://gateway-host/api/protected常见坑与排查
1. 阻塞操作导致性能下降
GlobalFilter 运行在响应式线程池中,严禁在 filter 方法中进行同步阻塞操作(如 JDBC 查询、HTTP 同步请求)。如果需要调用外部鉴权服务,必须使用 WebClient 等异步客户端。
2. 响应体写入时机
在 WebFlux 中,一旦响应提交(setComplete),就不能再修改响应体。错误信息必须在 writeWith 中写入,并设置正确的 Content-Type 为 application/json。
3. 过滤器顺序冲突
如果项目中存在多个全局过滤器,顺序设置不当可能导致鉴权在日志记录之前执行。发现逻辑不生效时,优先检查 getOrder 返回值。