插件窝 干货文章 Nginx反向代理中基于HTTP动词和路径的ACL配置

Nginx反向代理中基于HTTP动词和路径的ACL配置

method location HTTP server 974    来源:    2025-04-20

Nginx反向代理中基于HTTP动词和路径的ACL配置

在Nginx中实现基于HTTP方法(GET/POST/PUT/DELETE等)和请求路径的访问控制(ACL)可以通过多种方式实现。以下是几种常见的配置方法:

1. 使用$request_method变量和location

server {
    listen 80;
    server_name example.com;

    # 允许所有GET请求到/public路径
    location /public {
        if ($request_method !~ ^(GET|HEAD)$ ) {
            return 405;
        }
        proxy_pass http://backend;
    }

    # 只允许POST请求到/api/submit
    location = /api/submit {
        if ($request_method != POST) {
            return 405;
        }
        proxy_pass http://backend;
    }

    # 允许GET和DELETE到/resources
    location /resources {
        if ($request_method !~ ^(GET|DELETE)$ ) {
            return 405;
        }
        proxy_pass http://backend;
    }
}

2. 使用limit_except指令

server {
    listen 80;
    server_name example.com;

    # 只允许GET和HEAD方法
    location /read-only {
        limit_except GET HEAD {
            deny all;
        }
        proxy_pass http://backend;
    }

    # 允许POST和PUT方法
    location /write {
        limit_except POST PUT {
            deny all;
        }
        proxy_pass http://backend;
    }
}

3. 结合map指令实现更复杂的ACL

# 定义允许的方法映射
map $request_method $method_allowed {
    default         0;
    "GET"           1;
    "POST"          1;
    "HEAD"          1;
    "OPTIONS"       1;
}

# 定义路径和方法组合的ACL
map "$uri:$request_method" $acl {
    default                                 0;
    "~/api/users:GET"                       1;
    "~/api/users:POST"                     1;
    "~/api/users/[0-9]+:GET"               1;
    "~/api/users/[0-9]+:PUT"               1;
    "~/api/users/[0-9]+:DELETE"            1;
    "~/public/.*:GET"                      1;
}

server {
    listen 80;
    server_name example.com;

    location / {
        # 检查ACL
        if ($acl = 0) {
            return 403;
        }

        proxy_pass http://backend;
    }
}

4. 使用Lua脚本实现动态ACL(需要OpenResty)

server {
    listen 80;
    server_name example.com;

    location / {
        access_by_lua_block {
            local acl = {
                ["GET"] = {
                    ["^/public/.*"] = true,
                    ["^/api/info"] = true
                },
                ["POST"] = {
                    ["^/api/submit"] = true
                },
                ["DELETE"] = {
                    ["^/api/resource/%d+"] = true
                }
            }

            local method = ngx.req.get_method()
            local path = ngx.var.uri

            if not acl[method] then
                ngx.exit(ngx.HTTP_FORBIDDEN)
            end

            local allowed = false
            for pattern, _ in pairs(acl[method]) do
                if ngx.re.match(path, pattern) then
                    allowed = true
                    break
                end
            end

            if not allowed then
                ngx.exit(ngx.HTTP_FORBIDDEN)
            end
        }

        proxy_pass http://backend;
    }
}

最佳实践建议

  1. 安全性:对于敏感操作,除了方法限制外,还应结合认证和授权机制
  2. 性能:复杂的正则匹配会影响性能,尽量简化匹配规则
  3. 日志记录:记录被拒绝的请求以便审计

    log_format acl_log '$remote_addr - $remote_user [$time_local] '
                      '"$request" $status $body_bytes_sent '
                      '"$http_referer" "$http_user_agent" "$request_method"';
    
    server {
       access_log /var/log/nginx/acl.log acl_log;
    }
    
  4. 错误处理:提供有意义的错误响应 nginx error_page 403 = @method_not_allowed; location @method_not_allowed { return 403 '{"error": "Method not allowed for this resource"}'; }

这些配置可以根据实际需求组合使用,构建出适合您应用场景的访问控制策略。