一、背景与问题
在对外提供 API 服务时,匿名请求滥用是一个常见的安全问题。恶意脚本或未授权客户端可能通过大量调用消耗服务资源,导致以下后果:
云服务免费额度被迅速耗尽,产生额外费用
后端服务负载异常升高,影响正常用户访问
日志中充斥大量无效请求,干扰监控与排障
常见的解决方案及其局限性:
| 方案 | 局限性 |
|---|---|
| 业务代码中集成 JWT 中间件 | 需要修改代码、重新编译部署,涉及发版流程 |
| 云厂商 API 网关 | 商用产品需额外付费,配置规则复杂,有学习成本 |
| 自建鉴权服务 | 开发周期长,需考虑高可用、扩容等运维问题 |
上述方案均存在不同程度的改造成本或使用门槛。本文介绍一种基于 Nginx 原生能力的轻量级鉴权方案,只需两行核心配置即可在流量到达业务服务器之前完成身份验证。
二、方案概述
Nginx 提供了auth_request模块,该模块允许对每个请求发起一个内部子请求到指定的验证服务端点,根据该子请求的 HTTP 状态码决定是否放行原始请求。
核心逻辑:
原始请求 → Nginx 拦截 → 发起内部子请求至验证服务
→ 子请求返回 200 → 放行,代理至后端业务
→ 子请求返回 401/403 → 拒绝,直接返回客户端
该方案的关键优势在于:鉴权逻辑与业务逻辑完全解耦,Nginx 层面完成拦截与转发决策,后端业务服务无需任何改造。
三、配置步骤
第一步:在受保护的路由中启用 auth_request
location /api/ { # 开启鉴权子请求,指向内部验证端点 auth_request /gatekeeper-verify; # 代理至实际后端服务 proxy_pass http://your-backend-service:8080; # 透传原始请求头,便于后端获取真实客户端信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }参数说明:
auth_request /gatekeeper-verify:声明对每个/api/下的请求,Nginx 都会先发起一个到/gatekeeper-verify的内部子请求。proxy_pass:指向实际的业务后端地址,仅在鉴权通过后才会执行。
第二步:定义内部验证端点
location = /gatekeeper-verify { # 标记为内部接口,外部请求直接访问会返回 404 internal; # 转发子请求至独立的鉴权服务 proxy_pass https://your-auth-server.com/api/v1/verify; # 不转发请求体,减少鉴权服务的 I/O 开销 proxy_pass_request_body off; # 必须清空 Content-Length,因为禁用了请求体转发 proxy_set_header Content-Length ""; # 透传原始请求中的 Authorization 头(支持 Bearer Token) proxy_set_header Authorization $http_authorization; # 可选的固定内部校验密钥,防止验证服务被直接调用 proxy_set_header X-Internal-Secret "your-internal-secret"; # 设置超时时间,避免验证服务故障导致请求积压 proxy_connect_timeout 3s; proxy_read_timeout 5s; }配置要点:
| 指令 | 作用 |
|---|---|
internal; | 该端点仅接受 Nginx 内部子请求,外部访问无效 |
proxy_pass_request_body off; | 不转发请求体,仅验证 Header 中的凭证信息 |
proxy_set_header Content-Length ""; | 配合proxy_pass_request_body off使用,避免协议错误 |
proxy_set_header Authorization $http_authorization; | 将原始请求中的 Authorization 头原样传递给鉴权服务,支持 Bearer Token 或 Basic Auth |
proxy_*_timeout | 建议设置合理超时,防止鉴权服务不可用时阻塞业务 |
关于凭证传递方式:
上述配置直接透传Authorization头,因此客户端可按照标准 OAuth2/Bearer Token 规范在请求头中携带Authorization: Bearer <token>。如果您的系统使用自定义 API-Key(如X-API-Key),可将proxy_set_header Authorization替换为proxy_set_header X-API-Key $http_x_api_key,或同时透传多个头以满足不同鉴权策略。
第三步:重载配置生效
nginx -t # 检查配置文件语法 nginx -s reload # 热重载,无需重启 Nginx 主进程四、方案优势总结
业务零侵入:后端服务无需任何代码变更,无需重新编译或部署,适合已上线系统的快速加固。
配置热生效:修改 Nginx 配置后执行
reload即可生效,不影响现有连接。性能损耗小:子请求由 Nginx 内部处理,开销远低于引入独立网关代理。
运维成本低:验证服务可独立部署、独立扩缩容,与业务服务解耦。
故障隔离:验证服务超时或异常时,Nginx 可配置兜底策略(如
auth_request_set配合变量处理),避免级联故障。
五、注意事项
| 注意点 | 说明 |
|---|---|
| 鉴权服务高可用 | 验证服务故障可能导致所有请求被拒绝,建议部署多节点并使用负载均衡。 |
| 超时时间设置 | 需根据鉴权服务的 P99 延迟合理设置proxy_connect_timeout和proxy_read_timeout。 |
| 缓存机制 | 可在 Nginx 层面配合proxy_cache缓存鉴权结果,减少重复验证开销(适用于有效期较长的 Token)。 |
| HTTPS 加密 | 生产环境建议验证服务使用 HTTPS,防止凭证在传输中被截获。 |
| 日志审计 | 可在location = /gatekeeper-verify中启用访问日志,记录鉴权请求用于审计。 |
| Token 提取 | 若鉴权服务需要仅提取 Bearer Token 字符串,可考虑在服务端解析Authorization头,或通过 Nginx 变量$http_authorization传递完整头信息。 |
六、结语
auth_request是 Nginx 生态中一个成熟且稳定的模块,通过极小的配置成本即可为 API 服务构建一层身份验证屏障。该方案已在多家互联网公司的生产环境中得到验证,适用于微服务网关、API 暴露保护、多环境隔离等场景。