phantom-token: Phantom Token NGINX 模块
安装
您可以在任何基于 RHEL 的发行版中安装此模块,包括但不限于:
- RedHat Enterprise Linux 7, 8, 9 和 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 和 Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-phantom-token
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-phantom-token
通过在 /etc/nginx/nginx.conf 顶部添加以下内容来启用模块:
load_module modules/ngx_curity_http_phantom_token_module.so;
本文档描述了 nginx-module-phantom-token v2.0.0,于 2025 年 5 月 22 日发布。
NGINX 模块根据 RFC 7662 检查访问令牌,生成可以转发到后端 API 和 Web 服务的“幻影令牌”。有关 幻影令牌方法 的更多信息。
启用此模块后,它会过滤传入请求,拒绝那些未在 Authorization 头中提供有效 OAuth 访问令牌的请求。从该头中提取 access_token,并使用配置的端点进行检查。Curity 身份服务器根据标准回复此请求。对于有效的访问令牌,Curity 身份服务器响应的主体包含替换 NGINX 转发到后端请求头中的访问令牌的 JWT。如果令牌无效或缺失,则不会向后端发出请求,调用者将收到 401 未授权错误。此流程在以下图中显示:

应用程序(Web 或原生)的初始调用使用 OpenID Connect (OIDC)。重要的是,发出的令牌是一个不透明的访问令牌。它是一个 GUID 或 UUID 或一些随机字节;此令牌中没有与身份相关的数据。它是实际用户数据的一个 幻影,因此得名——幻影令牌。应用程序根据 Bearer Token Usage 规范(即 RFC 6750)将令牌呈现给 NGINX 网关。该标准规定,应用程序应在 Authorization 请求头中发送幻影令牌。
一旦 NGINX 服务器接收到访问令牌,此模块将启动。使用如下配置,此模块将检查请求,找到令牌,并向 Curity 身份服务器发出侧向调用。此 Web 服务请求将使用 Token Introspection 标准 (RFC 7662),并将 Accept 类型设置为 application/jwt(如 RFC 7519 中定义)。这将导致 Curity 身份服务器返回的不是 JSON,而只是一个 JWT。然后,该模块将 JWT 令牌转发到后端 API 和微服务。
如果模块还配置为缓存对 Curity 身份服务器调用的结果(在生产情况下应该这样配置),则幻影令牌将用作相应 JWT 令牌的缓存键。这将消除对 Curity 身份服务器的后续调用,只要它告知 NGINX 模块可以缓存 JWT。
简而言之,这是一个非常简单的 API 网关,速度极快,具有高度可扩展性,没有任何干扰的附加功能。所有代码都在这里,因此很容易更改并与其他 OAuth 服务器一起使用!
模块配置指令
版本 2.0 引入了 BREAKING CHANGE,以使用更新的配置指令。\ 请参见 以前的配置说明 来配置旧版本。
必需的配置指令
本小节中的指令是必需的;如果省略其中任何一个,模块将被禁用。
phantom_token
语法:
phantom_tokenon|off默认值:
off上下文:
location
phantom_token_introspection_endpoint
语法:
phantom_token_introspection_endpointstring默认值:
—上下文:
location
可选的配置指令
以下指令是可选的,不需要配置。
phantom_token_realm
语法:
phantom_token_realmstring默认值:
api上下文:
location
当客户端未提供访问令牌时,应该使用的受保护领域或保护范围的名称。
示例配置:
location / {
...
phantom_token_realm "myGoodRealm";
}
phantom_token_scopes
语法:
phantom_token_scopesstring默认值:
—上下文:
location
服务器应告知客户端在未提供访问令牌时所需的范围的以空格分隔的列表。
示例配置:
location / {
...
phantom_token_scopes "scope_a scope_b scope_c";
}
phantom_token_scope
语法:
phantom_token_scopestring默认值:
—上下文:
location
服务器应告知客户端在未提供访问令牌时所需的范围数组。如果同时配置了 phantom_token_scopes,则该值将优先于这些。
示例配置:
location / {
...
phantom_token_scope "scope_a";
phantom_token_scope "scope_b";
phantom_token_scope "scope_c";
}
示例配置
加载模块
如果模块是从 GitHub 下载或作为共享库(默认)编译,而不是显式编译到 NGINX 中,则需要使用 load_module 指令加载它。这需要在 NGINX 配置的 main 部分完成:
load_module modules/ngx_curity_http_phantom_token_module.so;
文件可以是绝对路径或相对路径。如果不是绝对路径,则应相对于 NGINX 根目录。
NGINX 参数用于检查端点
您还必须为检查子请求配置以下 NGINX 参数:
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_pass "https://curity.example.com/oauth/v2/oauth-introspect";
}
| 检查设置 | 描述 |
|---|---|
| internal | 防止检查端点在外部可用。 |
| proxy_pass_request_headers | 设置为 off,以避免在检查子请求中使用主请求的头部。 |
| Accept 头 | 配置固定值为 application/jwt。 |
| Content-Type 头 | 配置固定值为 application/x-www-form-urlencoded。 |
| Authorization 头 | 配置带有检查客户端 ID 和客户端密钥的基本凭证。 |
要获取基本凭证,请将客户端 ID、冒号字符和客户端密钥连接起来,然后进行 base64 编码。以下命令提供了一个示例。
echo -n "my_client_id:my_client_secret" | base64
简单配置
以下是一个简单配置,可能用于演示或开发环境,其中 NGINX 反向代理与 Curity 身份服务器在同一主机上:
server {
location /api {
phantom_token on;
phantom_token_introspection_endpoint curity;
proxy_pass https://example.com/api;
}
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_pass "https://curity.example.com/oauth/v2/oauth-introspect";
}
}
复杂配置
以下是一个更复杂的配置,其中 NGINX 反向代理与 Curity 身份服务器在不同的主机上:
server {
server_name server1.example.com;
location /api {
phantom_token on;
phantom_token_introspection_endpoint curity;
phantom_token_realm "myGoodAPI";
phantom_token_scopes "scope_a scope_b scope_c";
proxy_pass https://example.com/api;
}
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
}
}
server {
listen 8443;
server_name server2.example.com;
location / {
proxy_pass "https://curity.example.com";
}
}
更高级的配置,带有独立服务器和缓存
此模块利用了 NGINX 内置的 proxy_cache 指令。为了能够缓存对检查端点的请求,除了在 http 上下文中使用 proxy_cache_path 和在 location 上下文中使用 proxy_cache,您还必须在检查端点的 location 上下文中添加以下 3 个指令。
proxy_cache_methods POST;POST 请求默认不被缓存。proxy_cache_key $request_body;缓存的键与原始请求中发送的 access_token 相关。使用相同 access_token 的不同请求将达到相同的缓存。proxy_ignore_headers Set-Cookie;如果不忽略Set-Cookie头,NGINX 将不会缓存响应。
http {
proxy_cache_path /path/to/cache/cache levels=1:2 keys_zone=my_cache:10m max_size=10g
inactive=60m use_temp_path=off;
server {
server_name server1.example.com;
location /api {
phantom_token on;
phantom_token_introspection_endpoint curity;
phantom_token_scopes "scope_a scope_b scope_c";
phantom_token_realm "myGoodAPI";
proxy_pass https://example.com/api;
}
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_cache_methods POST;
proxy_cache my_cache;
proxy_cache_key $request_body;
proxy_ignore_headers Set-Cookie;
proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
}
}
server {
listen 8443;
server_name server2.example.com;
location / {
proxy_pass "https://curity.example.com";
}
}
}
无缓存配置
建议缓存对 Curity 身份服务器的调用结果,以避免对每个 API 请求触发检查请求。如果您希望禁用缓存,应扩展默认的 proxy_buffer_size,以确保模块可以读取大型 JWT。通过更新检查请求的配置来做到这一点,如以下示例所示。
http {
server {
server_name server1.example.com;
location /api {
phantom_token on;
phantom_token_introspection_endpoint curity;
phantom_token_scopes "scope_a scope_b scope_c";
phantom_token_realm "myGoodAPI";
proxy_pass https://example.com/api;
}
location curity {
internal;
proxy_pass_request_headers off;
proxy_set_header Accept "application/jwt";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Basic bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ=";
proxy_ignore_headers Set-Cookie;
proxy_buffer_size 16k;
proxy_buffers 4 16k;
proxy_pass "https://server2.example.com:8443/oauth/v2/oauth-introspect";
}
}
server {
listen 8443;
server_name server2.example.com;
location / {
proxy_pass "https://curity.example.com";
}
}
}
更多信息
有关 Curity 身份服务器、其功能以及如何使用它为微服务发放幻影令牌的更多信息,请访问 curity.io。有关使用 Curity 身份服务器保护 API 访问的背景信息,请参见我们的 API 安全资源。
GitHub
您可以在 nginx-module-phantom-token 的 GitHub 仓库 中找到有关此模块的其他配置提示和文档。