Nginx 通过 proxy_intercept_errors 和 error_page 拦截后端返回的 401 状态码实现认证过期统一处理,或借助 auth_request 调用鉴权服务前置校验 Token 有效期,并配合日志标识、Cookie 安全设置与前端协同提升体验。

当用户访问受保护资源时,如果认证已过期(如 JWT 过期、Session 失效、Token 无效),Nginx 本身不直接管理认证生命周期,但可以通过合理配置,将过期判断交由后端处理,并对返回的特定状态码(如 401 Unauthorized 或 403 Forbidden)做出统一响应,比如重定向到登录页或返回标准化错误。
利用 proxy_intercept_errors + error_page 拦截后端返回的过期响应
Nginx 不解析 Token,但能识别后端返回的 HTTP 状态码。若后端在检测到 Token 过期后返回 401,可在 Nginx 中拦截并跳转:
location /api/ {
proxy_pass http://backend;
proxy_intercept_errors on;
error_page 401 = @handle_unauthorized;
}
<p>location @handle_unauthorized {
return 302 <a href="https://www.php.cn/link/6ff20c6342d31611a5417e5aa8c3a1ba">https://www.php.cn/link/6ff20c6342d31611a5417e5aa8c3a1ba</a>;
}</p>- proxy_intercept_errors on 是关键,否则 401 会直接透传给客户端
- error_page 401 = @handle_unauthorized 表示内部重定向(不改变浏览器 URL),配合 return 302 实现外部跳转
- $request_uri 保留原始路径,方便登录后跳回
配合后端返回标准错误体,用 auth_request 做前置校验(推荐用于 API)
若需在 Nginx 层更早拒绝过期请求(例如保护静态资源或避免请求到达后端),可用 auth_request 模块调用一个认证校验服务:
# 定义认证子请求
location = /auth {
internal;
proxy_pass http://auth-service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
<h1>受保护路径</h1><p>location /protected/ {
auth_request /auth;
auth_request_set $auth_status $upstream_status;
error_page 401 = @login;
error_page 403 = @forbidden;
...
}</p><p>location @login {
return 302 /login?next=$request_uri;
}</p>- auth-service 的
/verify接口负责解析并验证 Token 有效期,过期则返回 401 - Nginx 不缓存 auth 结果,每次请求都校验,适合对时效性要求高的场景
- 注意:该方式需后端提供轻量、低延迟的鉴权接口
设置 Cookie 过期时间与 Secure/HttpOnly 标志(辅助手段)
虽然 Nginx 不生成 Session,但可统一注入或改写响应头,确保前端 Cookie 设置合理:
# 在 proxy_pass 后添加 proxy_cookie_path / "/; Secure; HttpOnly; SameSite=Strict"; # 或根据后端 Set-Cookie 动态改写(需 lua-nginx-module)
- 显式声明 Secure 和 HttpOnly 提升 Cookie 安全性
- 配合前端逻辑,在 JS 中检查 Token 有效期,提前触发登出,减少过期请求
- Nginx 无法主动“删除”客户端 Cookie,但可通过覆盖空值或过期时间间接失效(如
Set-Cookie: token=; expires=Thu, 01 Jan 1970 00:00:00 GMT)
记录与调试过期请求(便于排查)
为区分正常未登录和认证过期,建议后端在响应头中携带明确标识,Nginx 可据此打日志:
log_format authlog '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'auth="$sent_http_x_auth_status" uri="$request_uri"';
<p>access_log /var/log/nginx/auth.log authlog;</p>- 后端在返回 401 时加上
X-Auth-Status: expired - 通过
$sent_http_x_auth_status记录具体原因,避免所有 401 都被笼统视为“未登录” - 结合日志分析,可发现 Token 刷新机制是否失效、客户端缓存旧 Token 等问题


















