Nginx能否基于TCP socket做单次授权透传后续所有HTTP请求?
Nginx HTTP/2 连接级授权实现方案
原生Nginx的auth_request模块默认是请求级校验,每一个HTTP请求都会触发一次后端授权调用,没有内置的连接级授权能力,但可以通过扩展模块实现你要的「TCP连接建立时仅校验一次、同连接后续所有HTTP请求直接放行」的效果,两种主流实现方案如下:
方案1:基于OpenResty Lua 模块实现(兼容性最好)
依赖OpenResty发行版或者已编译ngx_http_lua_module的Nginx,通过共享内存缓存连接授权结果:
http { # 定义10M共享内存缓存区,可存储数万条连接授权记录 lua_shared_dict conn_auth_cache 10m; # HTTP/2 空闲连接超时时间,和缓存过期时间对齐 http2_idle_timeout 300s; server { listen 443 ssl http2; # 其他站点配置省略 location /somewhere_restricted { access_by_lua_block { local conn_id = ngx.var.connection local auth_cache = ngx.shared.conn_auth_cache -- 优先查询当前连接是否已有授权记录 local is_authed = auth_cache:get(conn_id) if is_authed then return -- 已授权直接放行 end -- 无授权记录则调用后端授权接口 local auth_res = ngx.location.capture("/isallowed") if auth_res.status == 200 then -- 授权通过,缓存结果300秒,和HTTP/2空闲超时对齐 auth_cache:set(conn_id, 1, 300) return end -- 授权失败返回401 return ngx.exit(401) } } location = /isallowed { internal; proxy_pass http://backend_auth; # 不需要传递请求体,减少授权请求开销 proxy_pass_request_body off; proxy_set_header Content-Length ""; } } }
方案2:基于Nginx官方ngx_http_keyval_module实现(无Lua依赖)
需要Nginx版本≥1.19.8,无需额外编译Lua模块,配置更简洁:
http { # 定义连接授权缓存区,10M容量,缓存自动过期时间300s keyval_zone zone=conn_auth:10M timeout=300s; # 绑定连接ID为缓存key,$conn_auth_ok为缓存值(标识是否授权通过) keyval $connection $conn_auth_ok zone=conn_auth; # HTTP/2 空闲超时和缓存过期时间对齐 http2_idle_timeout 300s; server { listen 443 ssl http2; # 其他站点配置省略 location /somewhere_restricted { # 当前连接已有授权记录直接放行 if ($conn_auth_ok = 1) { break; } # 无授权记录走auth_request校验 auth_request /isallowed; # 校验通过后写入缓存 auth_request_set $conn_auth_ok 1; } location = /isallowed { internal; proxy_pass http://backend_auth; } } }
注意事项
- 上述方案仅适用于单个HTTP/2连接归属于单个用户的场景,如果客户端是代理服务、会复用连接传递多个用户的请求,会出现权限串用问题,需要业务侧保证连接和用户的绑定关系
- 缓存过期时间建议和
http2_idle_timeout严格对齐,避免连接断开后缓存残留浪费存储空间 - 该逻辑和WebSocket场景的授权逻辑本质一致:均是在长连接建立阶段完成一次性校验,后续同连接的所有流量直接放行
内容的提问来源于stack exchange,提问作者sTONES
相关产品推荐
相关产品推荐

