Nginx auth_request 模块使用

Nginx auth_request 模块使用笔记

📌 模块概述

nginx-auth-request-module(官方名:http_auth_request_module)用于在请求处理前向外部服务进行认证验证。

🔧 安装与启用

# 编译时添加模块
./configure --add-module=/path/to/nginx-auth-request-module

# 检查是否已安装
nginx -V 2>&1 | grep -o http_auth_request_module

🎯 基础配置

server {
    listen 80;
    server_name example.com;

    location / {
        auth_request /auth;  # 认证检查
        error_page 401 = @error401;  # 认证失败处理
        proxy_pass http://backend;  # 后端服务
    }

    location = /auth {
        internal;  # 内部访问
        proxy_pass http://auth-service/validate;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
    }

    location @error401 {
        return 302 /login?redirect=$request_uri;
    }
}

📊 认证服务要求

状态 HTTP状态码 说明
认证成功 200 允许访问
认证失败 401 未认证
认证失败 403 无权限

⚠️ 常见问题:JSON状态码处理

当认证服务返回JSON格式的状态码时(如 {"code": 401, "msg": "认证失败"}),需要特殊处理:

方案1:修改认证服务(推荐✅)

// 认证服务直接返回正确的HTTP状态码
app.get('/validate', (req, res) => {
    if (!isAuthenticated(req)) {
        return res.status(401).json({  // 直接设置HTTP状态码
            code: 401,
            msg: "认证失败"
        });
    }
    res.status(200).json({ code: 200 });
});

方案2:使用Lua处理(需要OpenResty)

location = /auth {
    internal;
    proxy_pass http://auth-service/validate;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    
    header_filter_by_lua_block {
        local resp_body = ngx.var.upstream_resp_body
        if resp_body then
            local cjson = require "cjson"
            local ok, data = pcall(cjson.decode, resp_body)
            if ok and data and data.code == 401 then
                ngx.status = 401  # 覆盖状态码
            end
        end
    }
}

🚀 高级功能

1. 传递用户信息

location / {
    auth_request /auth;
    auth_request_set $user $upstream_http_x_auth_user;
    auth_request_set $roles $upstream_http_x_auth_roles;
    
    proxy_set_header X-User $user;
    proxy_set_header X-Roles $roles;
    proxy_pass http://backend;
}

2. 认证缓存

http {
    auth_request_cache_zone shared:auth_cache 10m;
    
    server {
        location / {
            auth_request /auth;
            auth_request_cache shared:auth_cache;
            auth_request_cache_key "$cookie_sessionid";
            auth_request_cache_valid 200 5m;
            
            proxy_pass http://backend;
        }
    }
}

3. 完整头信息传递

location = /auth {
    internal;
    proxy_pass http://auth-service/validate;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    
    # 传递所有相关信息
    proxy_set_header X-Original-Method $request_method;
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Original-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header Authorization $http_authorization;
    proxy_set_header Cookie $http_cookie;
}

🔍 调试技巧

# 添加调试头信息
add_header X-Auth-Status $upstream_status;
add_header X-Auth-User $user;
add_header X-Auth-Roles $roles;

# 日志记录
log_format auth_log '$remote_addr - $user [$time_local] '
                   '"$request" $status $body_bytes_sent '
                   '"$http_referer" "$http_user_agent" '
                   'auth_status:$upstream_status';

access_log /var/log/nginx/auth.log auth_log;

🛡️ 安全考虑

  1. 超时设置:避免认证服务不可用导致阻塞

    proxy_connect_timeout 3s;
    proxy_read_timeout 5s;
    
  2. 错误处理:认证服务宕机时的降级策略

    location = /auth {
        proxy_next_upstream error timeout invalid_header;
        proxy_intercept_errors on;
        error_page 500 502 503 504 = @auth_service_down;
    }
    
    location @auth_service_down {
        # 允许访问或拒绝所有请求
        return 200;  # 或 return 403;
    }
    

📋 最佳实践

  1. ✅ 认证服务直接返回HTTP状态码
  2. ✅ 使用HTTPS保护认证请求
  3. ✅ 设置合理的超时时间
  4. ✅ 实现认证服务的健康检查
  5. ✅ 记录详细的认证日志
  6. ❌ 避免在认证请求中传递敏感数据

🎪 应用场景

场景 配置特点
JWT认证 传递Authorization头,验证token
角色控制 基于返回的角色头信息进行权限判断
多因素认证 链式认证请求
API网关 统一认证所有后端服务

总结:优先让认证服务返回正确的HTTP状态码,如无法修改再考虑使用Lua/NJS处理JSON响应。合理配置缓存和超时以确保系统稳定性。

posted @ 2025-09-16 17:27  槑孒  阅读(130)  评论(0)    收藏  举报