跳到主要内容

forward-auth

forward-auth 插件支持与外部授权服务集成以进行认证和授权。如果认证失败,将向客户端返回可自定义的错误消息。如果认证成功,请求将连同 APISIX 添加的以下请求头一起转发到上游服务:

  • X-Forwarded-Proto: 协议
  • X-Forwarded-Method: HTTP 方法
  • X-Forwarded-Host: 主机
  • X-Forwarded-Uri: URI
  • X-Forwarded-For: 源 IP

示例

以下示例演示了如何在不同场景下使用 forward-auth

要跟随前两个示例,请先设置好你的外部授权服务,或者使用 serverless function 插件 创建一个模拟认证服务,如下所示:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"id": "auth-mock",
"uri": "/auth",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function (conf, ctx)
local core = require(\"apisix.core\");
local authorization = core.request.header(ctx, \"Authorization\");
if authorization == \"123\" then
core.response.exit(200);
elseif authorization == \"321\" then
core.response.set_header(\"X-User-ID\", \"i-am-user\");
core.response.exit(200);
else core.response.set_header(\"X-Forward-Auth\", \"Fail\");
core.response.exit(403);
end
end"
]
}
}
}'

上述函数实现了以下逻辑:

❶ 如果 Authorization 头的值为 123,响应 200 OK

❷ 如果 Authorization 头的值为 321,设置头 X-User-ID: i-am-user 并响应 200 OK

❸ 否则,设置头 X-Forward-Auth: Fail 并响应 403 Forbidden

转发指定头到上游资源

以下示例演示了如何在路由上设置 forward-auth,根据请求头中的值控制客户端对上游资源的访问。它还允许将授权服务中的特定头传递到上游资源。

创建一个启用了 forward-auth 插件的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "forward-auth-route",
"uri": "/headers",
"plugins": {
"forward-auth": {
"uri": "http://127.0.0.1:9080/auth",
"request_headers": ["Authorization"],
"upstream_headers": ["X-User-ID"]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'

❶ 授权服务的 URI。

❷ 需要转发到授权服务的请求头。

❸ 当授权成功时,需要从授权服务转发到上游资源的请求头。

向路由发送带有授权详情的请求:

curl "http://127.0.0.1:9080/headers" -H 'Authorization: 123'

你应该会看到如下的 HTTP/1.1 200 OK 响应:

{
"headers": {
"Accept": "*/*",
"Authorization": "123",
...
}
}

要验证授权服务设置的 X-User-ID 头是否转发到了上游服务,请发送带有相应授权详情的请求:

curl "http://127.0.0.1:9080/headers" -H 'Authorization: 321'

你应该会看到如下的 HTTP/1.1 200 OK 响应,显示该头已转发到上游:

{
"headers": {
"Accept": "*/*",
"Authorization": "123",
"X-User-ID": "i-am-user",
...
}
}

认证失败时返回指定头给客户端

以下示例演示了如何在路由上配置 forward-auth 以控制客户端对上游资源的访问。当认证失败时,它还会将授权服务返回的特定头传递给客户端。

创建一个启用了 forward-auth 插件的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "forward-auth-route",
"uri": "/headers",
"plugins": {
"forward-auth": {
"uri": "http://127.0.0.1:9080/auth",
"request_headers": ["Authorization"],
"client_headers": ["X-Forward-Auth"]
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'

❶ 当认证失败时,将来自授权服务的 X-Forward-Auth 头传回给客户端。

发送一个不带任何认证信息的请求:

curl -i "http://127.0.0.1:9080/headers"

你应该收到一个 HTTP/1.1 403 Forbidden 响应:

...
X-Forward-Auth: Fail
Server: APISIX/3.x.x

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty</center>
<p><em>Powered by <a href="https://apisix.apache.org/">APISIX</a>.</em></p></body>
</html>

基于 POST Body 进行授权

此示例演示了如何配置 forward-auth 插件以根据 POST Body 数据控制访问,将值作为头传递给授权服务,并在根据 Body 数据授权失败时拒绝请求。

请先设置好你的外部授权服务,或者使用 serverless function 插件 创建一个模拟认证服务。该函数检查 tenant_id 头是否为 123,如果是则返回 200 OK,否则返回 403 错误。

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"id": "auth-mock",
"uri": "/auth",
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function(conf, ctx)
local core = require(\"apisix.core\")
local tenant_id = core.request.header(ctx, \"tenant_id\")
if tenant_id == \"123\" then
core.response.exit(200);
else
core.response.exit(403, \"tenant_id is \"..tenant_id .. \" but expecting 123\");
end
end"
]
}
}
}'

创建一个启用了 forward-auth 插件的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "forward-auth-route",
"uri": "/post",
"methods": ["POST"],
"plugins": {
"forward-auth": {
"uri": "http://127.0.0.1:9080/auth",
"request_method": "GET",
"extra_headers": {"tenant_id": "$post_arg.tenant_id"}
}
},
"upstream": {
"nodes": {
"httpbin.org:80": 1
},
"type": "roundrobin"
}
}'

❶ 使用 POST 参数 tenant_id 的值设置额外的头 tenant_id

发送一个 Body 中包含 tenant_id 的 POST 请求:

curl -i "http://127.0.0.1:9080/post" -X POST -d '
{
"tenant_id": "123"
}'

你应该收到一个 HTTP/1.1 200 OK 响应。

发送一个 Body 中包含错误 tenant_id 的 POST 请求:

curl -i "http://127.0.0.1:9080/post" -X POST -d '
{
"tenant_id": "000"
}'

你应该收到如下的 HTTP/1.1 403 Forbidden 响应:

tenant_id is 000 but expecting 123