大多数情况下,这是因为路径匹配规则与请求实际 URI 不一致,或者鉴权过滤器的执行顺序早于放行逻辑。
先说结论:配置失效通常不是代码错误,而是匹配模式或执行优先级问题,需优先检查路径语法和过滤器顺序。
- 先确认:放行路径使用的是 Ant 风格还是正则,是否包含上下文路径。
- 先处理:调整鉴权过滤器 Order 值,确保放行判断逻辑优先执行。
- 再验证:通过日志观察请求是否命中放行规则,再测试接口访问。
核心原因分析
网关鉴权通常是通过过滤器链(Filter Chain)实现的。请求进来后,会依次经过多个过滤器。如果鉴权过滤器的执行顺序排在放行判断之前,那么即使配置了放行路径,请求也会先被鉴权逻辑拦截。
另外,路径匹配机制也存在差异。Spring Cloud Gateway 默认使用 PathPatternParser,支持 * 和 ** 通配符。如果配置的是 /api/public/* 但实际请求是 /api/public/user/info,单层星号无法匹配多层路径。此外,URL 编码也可能导致匹配失败,例如空格被编码为 %20,而配置中写的是空格。
推荐优先使用 Ant 风格路径匹配,在配置一致性上比正则更容易维护。
Spring Cloud Gateway 解决方案
以下是基于 Spring Cloud Gateway 的标准排查与修复步骤,包含配置绑定与过滤器实现。
第一步:核对路径匹配模式与配置绑定
检查配置文件中的放行路径。自定义白名单配置需要代码支持才能生效,以下是标准的 YAML 配置与 Java 绑定示例:
# application.yml 配置示例
custom:
auth:
skip-paths:
- /api/public/**
- /health/**在代码中通过 @ConfigurationProperties 或 @Value 读取该配置,确保配置键与代码一致:
@Component
public class AuthFilter implements GlobalFilter, Ordered {
// 读取配置中的白名单路径
@Value("${custom.auth.skip-paths}")
private List<String> skipPaths;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getPath().value();
// 匹配逻辑
if (skipPaths.stream().anyMatch(pattern -> new AntPathMatcher().match(pattern, path))) {
return chain.filter(exchange); // 放行
}
// 继续鉴权逻辑...
return chain.filter(exchange);
}
@Override
public int getOrder() {
// 数值越小优先级越高,需确保小于实际鉴权逻辑的 Order
// 避免使用 -1,防止与 NettyWriteResponseFilter 等系统过滤器冲突
return -100;
}
}第二步:调整过滤器顺序
如果是自定义代码实现的鉴权过滤器,检查 @Order 注解或 getOrder() 方法返回值。放行逻辑应该在鉴权逻辑之前执行。
注意:硬编码 -1 可能与框架内置过滤器(如 NettyWriteResponseFilter)冲突。建议定义常量管理顺序,例如 AuthOrder.WHITE_LIST = -100,AuthOrder.AUTH_CHECK = 0。
第三步:检查 URL 编码影响
部分网关在匹配前会对 URI 进行解码,部分则不会。如果配置中包含特殊字符,建议统一使用解码后的路径进行配置,并在测试时使用浏览器直接访问而非 curl 编码后的地址。
Kong/APISIX 配置参考
如果您使用的是 Kong 或 APISIX,配置方式与 Spring Cloud Gateway 不同,需检查 Plugin 的执行优先级。
Kong 配置示例:
# 启用 key-auth 插件并配置白名单
curl -X POST http://kong:8001/services/{service}/plugins \
`--data` "name=key-auth" \
`--data` "config.key_names=apikey" \
`--data` "config.hide_credentials=true"在 Kong 中,需通过 config.skip_consumer 或前置插件逻辑实现放行,具体取决于使用的鉴权插件版本。
APISIX 配置示例:
# 在路由配置中设置 plugin_attr 或使用 consumer 插件
{
"uri": "/api/public/*",
"plugins": {
"key-auth": { "disable": true }
}
}验证与排查
1. 日志观察
开启网关应用的 DEBUG 级别日志,重点关注过滤器链的执行记录。寻找类似 Skipping auth for path 或 Matched whitelist 的日志输出。如果没有看到放行日志却看到了鉴权失败日志,说明匹配未生效。
2. curl 测试
使用 curl 命令访问放行路径,观察返回状态码。预期应该是 200 或直接透传到后端,而不是 401/403。
curl -v http://gateway-host/api/public/test如果返回 401,说明鉴权拦截依然生效。
3. 后端验证
在后端服务中打印请求头。如果鉴权生效,通常会有特定的 Token 头;如果放行,可能没有 Token 头但请求依然到达后端。确认后端是否收到了请求。
常见坑
1. 末尾斜杠问题
配置 /api/public 时,请求 /api/public/ 可能被视为不同路径。建议在配置中统一是否包含末尾斜杠,或在网关层开启忽略末尾斜杠的配置。
2. 配置热更新未生效
如果使用了配置中心(如 Nacos、Apollo),修改放行路径后需确认配置是否已推送并刷新。部分网关过滤器在启动时加载配置,运行时修改可能不生效,需要重启服务。
3. 大小写敏感
路径匹配默认通常是大小写敏感的。配置 /API/public 无法匹配 /api/public。确保配置与请求路径的大小写完全一致。
4. 多过滤器冲突
如果网关中引入了多个安全相关插件(如 CORS 插件、限流插件、鉴权插件),它们之间可能存在顺序冲突。确保放行逻辑在所有安全拦截之前执行。