网关鉴权:统一 Token 校验与白名单
登录校验如果每个服务各做一遍,规则会越改越乱、漏网越来越多。网关是所有外部流量的必经入口,把鉴权放在网关做一次统一收口,后端服务就能专注于业务。本章实现"白名单放行 + Token 校验 + 用户上下文透传"的网关鉴权骨架。
前提认知:信任边界
网关鉴权解决的是"外部请求有没有资格进来"。但要清醒:服务之间的内部调用不经过网关(Feign 直连),所以"网关校验过"不等于"请求可信"。标准做法分两层:网关对公网请求做完整鉴权;服务间调用使用内部凭证或至少不盲目信任上游传入的业务头(第 22 章会讲头防伪)。若所有服务都强制走网关(严格拓扑),则另当别论。
两种 Token 校验风格
一是 JWT 自校验:网关用本地保存的公钥解析并验签 Token,无状态、不依赖认证中心在线,适合高并发网关;缺点是 Token 撤销不实时,依赖过期时间。二是调用认证中心校验:每次请求回调认证服务确认有效性,可实时踢人,但增加一次 RPC 与可用性依赖。常见组合:网关验 JWT 签名与有效期,拉黑/注销等强失效场景走短过期时间或 Redis 黑名单。具体选用哪种与你的认证体系绑定,本示例用校验服务接口抽象表示,不绑定实现。
白名单:先定义"不用登录"的路径
登录接口、验证码、回调、健康检查等路径天然无需 Token。把白名单做成可配置项(放 Nacos 即可动态调整,第 11 章):
app:
auth:
whitelist:
- /api/auth/login
- /api/auth/captcha
- /actuator/**
用一个 @ConfigurationProperties 类绑定该列表,网关过滤器按前缀匹配放行。
核心:鉴权 GlobalFilter
自定义全局过滤器,order 设为很小值保证最先执行:
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final AuthWhitelist whitelist;
private final TokenValidator tokenValidator;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
if (whitelist.matches(request.getURI().getPath())) {
return chain.filter(exchange); // 白名单直接放行
}
String token = resolveToken(request); // 依次取 Header/Cookie/Query
TokenClaims claims = tokenValidator.validate(token); // 无效则返回 null
if (claims == null) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete(); // 401 直接结束
}
// 覆盖式写入用户头,防止调用方伪造(先删后写)
ServerHttpRequest mutated = request.mutate()
.headers(h -> h.remove("X-User-Id"))
.header("X-User-Id", claims.getUserId())
.build();
return chain.filter(exchange.mutate().request(mutated).build());
}
@Override
public int getOrder() { return -200; }
}
要点:失败时用 401 表示"未认证"、403 表示"无权限",语义别混用;直接 setComplete 结束请求比抛异常更干净;透传给下游的用户标识要"覆盖写"而不是"追加写",杜绝客户端伪造 X-User-Id 冒充他人。
下游如何消费用户身份
后端服务从请求头读取网关写入的用户上下文(配合第 22 章的统一上下文组件),例如 user-service 的拦截器把 X-User-Id 放入 ThreadLocal 供业务使用。注意服务只该信任"自己人"写入的头——内部服务之间调用同样要带上身份并校验来源,别把网关头当作天然可信输入。
工程化补充
网关鉴权应做到无状态可水平扩展,公钥/黑名单等数据放配置中心或 Redis 而非网关本地内存;Token 解析与验签属于 CPU 密集操作,可加缓存与限流(第 10 章)防刷;登录、刷新、登出等端点本身放在白名单并由认证服务处理,网关不掺和会话细节。Token 格式、签名算法与密钥管理以你选用的认证库/规范文档为准。
小结
网关鉴权 = 白名单放行公共路径 + 全局过滤器校验 Token + 401 快速失败 + 覆盖式透传用户头。它把"你有没有资格"收敛到一处,后端专注"你是谁、能干什么"的授权逻辑。身份信息要随调用链继续传递,这正是下一章上下文透传的主题。