# ============================================================
# Nginx access_by_lua 认证配置示例
# ============================================================
#
# 功能说明:
# - 使用 Lua 实现访问控制
# - JWT 验证
# - 自定义认证逻辑
#
# Lolly 对应配置:
# 可通过 Lua 沙箱实现自定义认证中间件
# ============================================================

http {
    lua_shared_dict tokens 10m;

    server {
        listen 80;
        server_name auth-lua.example.com;

        # JWT 认证
        location /api {
            access_by_lua_block {
                local jwt = require "resty.jwt"

                -- 获取 Authorization 头
                local auth_header = ngx.var.http_authorization
                if not auth_header then
                    ngx.status = 401
                    ngx.header["WWW-Authenticate"] = 'Bearer realm="API"'
                    ngx.say('{"error": "Missing authorization header"}')
                    ngx.exit(401)
                end

                -- 解析 Bearer token
                local _, _, token = string.find(auth_header, "Bearer%s+(.+)")
                if not token then
                    ngx.status = 401
                    ngx.say('{"error": "Invalid token format"}')
                    ngx.exit(401)
                end

                -- 验证 JWT
                local jwt_obj = jwt:verify("secret-key", token)
                if not jwt_obj.verified then
                    ngx.status = 401
                    ngx.say('{"error": "Invalid token"}')
                    ngx.exit(401)
                end

                -- 将用户信息传递给后端
                ngx.req.set_header("X-User-ID", jwt_obj.payload.sub)
                ngx.req.set_header("X-User-Role", jwt_obj.payload.role)
            }

            proxy_pass http://backend:8080;
        }

        # API Key 认证
        location /api/v2 {
            access_by_lua_block {
                local api_key = ngx.var.http_x_api_key
                if not api_key then
                    ngx.status = 401
                    ngx.say('{"error": "Missing API key"}')
                    ngx.exit(401)
                end

                -- 从共享字典验证 API key
                local tokens = ngx.shared.tokens
                local user_id = tokens:get(api_key)

                if not user_id then
                    ngx.status = 401
                    ngx.say('{"error": "Invalid API key"}')
                    ngx.exit(401)
                end

                ngx.req.set_header("X-User-ID", user_id)
            }

            proxy_pass http://backend:8080;
        }

        # IP 白名单 + Token 认证
        location /admin {
            access_by_lua_block {
                local ip = ngx.var.remote_addr

                -- IP 白名单检查
                local whitelist = {
                    ["127.0.0.1"] = true,
                    ["10.0.0.0/8"] = true,  -- 需要额外处理 CIDR
                }

                if not whitelist[ip] then
                    -- 非 IP 白名单，需要 Token
                    local token = ngx.var.http_x_admin_token
                    if not token or token ~= "admin-secret" then
                        ngx.status = 403
                        ngx.say('{"error": "Access denied"}')
                        ngx.exit(403)
                    end
                end
            }

            proxy_pass http://admin-backend:8080;
        }
    }
}

# access_by_lua 说明:
#
# 1. 执行时机:
#    - 在 rewrite 阶段之后
#    - 在 content 阶段之前
#    - 可用于访问控制
#
# 2. 常用操作:
#    - ngx.exit(status): 终止请求，返回状态码
#    - ngx.say(body): 输出响应体
#    - ngx.req.set_header(): 设置请求头
#    - ngx.req.get_headers(): 获取请求头
#
# 3. 认证模式:
#    - JWT: 解析验证 JWT token
#    - API Key: 从共享字典验证
#    - Basic Auth: 自定义验证逻辑
#    - OAuth: 调用外部服务验证
#
# 4. 性能优化:
#    - 使用共享字典缓存验证结果
#    - 避免每次请求都访问外部服务
#    - 使用 cosocket 异步调用