跳到主要内容

acl

acl 插件用于根据发起请求的用户是否在访问控制列表(ACL)中,允许或拒绝对上游资源的访问。

示例

以下示例展示了如何在不同场景下使用 acl 插件。

通过检查消费者标签控制访问

以下示例展示了如何在成功认证后,根据消费者(Consumer)标签控制访问权限。

创建两个消费者 johnjane,并为他们分别配置所属组织和项目的标签:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "john",
"labels": {
"org": "[\"opensource\",\"apache\"]",
"project": "[\"tomcat\",\"web-server\",\"http,server\"]"
}
}'
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jane",
"labels": {
"org": "apache",
"project": "gateway,apisix,web-server"
}
}'

johnjane 创建 key-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jane-key-auth",
"plugins": {
"key-auth": {
"key": "jane-key"
}
}
}'
提示

消费者标签可以通过以下两种方式配置:

  1. 逗号分隔的字符串值,例如 {"project": "gateway,apisix"}
  2. 转义的字符串数组,例如 {"project": "[\"gateway\",\"apisix\"]"}

创建一个启用了 key-auth 的路由,并配置 acl 插件:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "acl-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"acl": {
"allow_labels": {
// Annotate 1
"org": ["opensource"]
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

❶ 仅允许 org 标签值为 opensource 的消费者访问上游资源。

以消费者 jane 的身份发送请求:

curl -i "http://127.0.0.1:9080/get" -H 'apikey: jane-key'

你应该会收到 HTTP/1.1 403 Forbidden 响应,因为消费者 jane 没有配置访问该路由所需的标签。

以消费者 john 的身份发送请求:

curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key'

你应该会收到 HTTP/1.1 200 OK 响应,因为消费者 john 配置了访问该路由所需的标签。

通过检查外部身份提供商的用户信息控制访问

以下示例展示了在通过外部身份提供商成功认证后,如何根据用户标签控制访问。具体来说,本示例使用 Keycloak 和用户组作为标签。

按照 使用 Keycloak 设置 SSO 指南 中的步骤创建 realm、client 和用户。

进入 Groups 并创建两个新组:apisixopensource

new-group

要将用户添加到组,请点击用户并进入 Groups 选项卡。依次选择每个组并点击 join

join-user-to-groups

要在从 Keycloak 请求用户信息时包含组成员资格,请进入 client 并转到 Mappers 选项卡。创建一个新的 mapper:

create-mapper

填写 protocol mapper 的名称,选择 Group Membership 作为 mapper 类型,使用 groups 作为 token claim 名称,然后点击 Save

save-protocol-mapper

要验证请求用户信息时是否可见该属性,首先从 Keycloak 获取访问令牌(access token):

OIDC_USER=quickstart-user
OIDC_PASSWORD=quickstart-user-pass
OIDC_CLIENT_ID=apisix-quickstart-client
OIDC_CLIENT_SECRET=bi9NFscFT4k0ljaRzQWlJWthrlygUn3x # 请替换为你的 client secret

curl "http://$KEYCLOAK_IP:8080/realms/quickstart-realm/protocol/openid-connect/token" -X POST \
-d 'grant_type=password' \
-d 'client_id='$OIDC_CLIENT_ID'' \
-d 'client_secret='$OIDC_CLIENT_SECRET'' \
-d 'username='$OIDC_USER'' \
-d 'password='$OIDC_PASSWORD''

将访问令牌保存到名为 ACCESS_TOKEN 的环境变量中,并使用该令牌向 Keycloak 用户信息端点发送请求:

curl "http://$KEYCLOAK_IP:8080/realms/quickstart-realm/protocol/openid-connect/userinfo" -H "Authorization: Bearer $ACCESS_TOKEN"

你应该会看到类似以下的响应:

{
"sub":"4310e97c-d4c3-479b-bbbd-8c66120e6cee",
"email_verified":false,
"groups":["/apisix", "/opensource"],
"preferred_username":"quickstart-user"
}

假设你只想允许 groups 属性包含 /apisix 值的用户访问上游资源。

创建一个包含 openid-connectacl 插件的路由:

KEYCLOAK_IP=192.168.1.81    # 请替换为你的主机 IP
OIDC_DISCOVERY=http://${KEYCLOAK_IP}:8080/realms/quickstart-realm/.well-known/openid-configuration

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "acl-route",
"uri":"/anything/*",
"plugins": {
"openid-connect": {
"bearer_only": true,
"client_id": "'"$OIDC_CLIENT_ID"'",
"client_secret": "'"$OIDC_CLIENT_SECRET"'",
"discovery": "'"$OIDC_DISCOVERY"'",
"scope": "openid profile",
"redirect_uri": "http://localhost:9080/anything/callback"
},
"acl": {
// Annotate 1
"external_user_label_field": "groups",
// Annotate 2
"allow_labels": {
"groups": ["/apisix"]
}
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"httpbin.org:80":1
}
}
}'

❶ 将 external_user_label_field 配置为映射到组的名称。

❷ 仅允许 groups 属性值为 /apisix 的用户访问上游资源。

使用有效的访问令牌向该路由发送请求:

curl -i "http://127.0.0.1:9080/anything/test" -H "Authorization: Bearer $ACCESS_TOKEN"

你应该会看到 HTTP/1.1 200 OK 响应,这验证了 API 调用已获得授权并允许访问上游资源。

要查看 acl 插件如何限制访问,请更新插件以要求用户信息中不包含的属性:

curl "http://127.0.0.1:9180/apisix/admin/routes/acl-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"acl": {
"allow_labels": {
"groups": ["foobar"]
}
}
}
}'

使用有效的访问令牌再次向同一路由发送请求:

curl -i "http://127.0.0.1:9080/anything/test" -H "Authorization: Bearer $ACCESS_TOKEN"

你应该会看到 HTTP/1.1 403 Forbidden 响应,表明访问受限。

通过检查外部身份提供商的嵌套用户信息控制访问

以下示例展示了如何配置 acl 插件以从嵌套的 JSON 结构中获取标签,并通过检查这些标签是否在白名单中来控制访问。

如果你使用 Keycloak 作为身份提供商,配置步骤与上一个示例类似,但在创建 Group Membership 时,将 Token Claim Name 配置为要在嵌套 JSON 对象中显示的组成员资格的完全限定名:

keycloak-nested-group-membership

警告

Keycloak 的早期版本存在 一个 bug,导致在请求用户信息时,Token Claim Name 中的点号被作为字符串字面量返回,而不是返回嵌套的 JSON 结构。请使用 Keycloak >= 23.0.0

接下来,请求用户访问令牌和用户信息,类似于上一个示例。你应该会看到 Keycloak 返回类似以下的用户信息:

{
"sub": "f62086ef-29e1-4401-8609-451a2d724bd7",
"email_verified": false,
"acl_labels": {
"nested": {
"groups": [
"/apisix",
"/opensource"
]
}
},
"preferred_username": "quickstart-user"
}

在 API7 中,创建一个带有 openid-connect 的路由以通过 Keycloak 进行认证,并配置 acl 插件:

KEYCLOAK_IP=192.168.1.81    # 请替换为你的主机 IP
OIDC_DISCOVERY=http://${KEYCLOAK_IP}:8080/realms/quickstart-realm/.well-known/openid-configuration

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "acl-route",
"uri":"/anything/*",
"plugins": {
"openid-connect": {
"bearer_only": true,
"client_id": "'"$OIDC_CLIENT_ID"'",
"client_secret": "'"$OIDC_CLIENT_SECRET"'",
"discovery": "'"$OIDC_DISCOVERY"'",
"scope": "openid profile",
"redirect_uri": "http://localhost:9080/anything/callback"
},
"acl": {
// Annotate 1
"external_user_label_field": "$..groups",
// Annotate 2
"external_user_label_field_key": "groups",
// Annotate 3
"external_user_label_field_parser": "json",
// Annotate 4
"allow_labels": {
"groups": ["/apisix"]
}
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"httpbin.org:80":1
}
}
}'

❶ 使用有效的 JSONPath 配置用户标签字段,指向包含标签的嵌套字段。

❷ 将字段键设置为嵌套字段的名称。

❸ 将解析器设置为 json,以便与用户信息数据结构保持一致。

❹ 仅允许 groups 属性值为 /apisix 的用户访问上游资源。

要验证 ACL,请使用有效的访问令牌向路由发送请求:

curl -i "http://127.0.0.1:9080/anything/test" -H "Authorization: Bearer $ACCESS_TOKEN"

你应该会看到 HTTP/1.1 200 OK 响应,表明 API 调用已获得授权并允许访问上游资源。

要查看 acl 插件如何限制访问,请更新插件以要求用户信息中不包含的属性:

curl "http://127.0.0.1:9180/apisix/admin/routes/acl-route" -X PATCH \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"plugins": {
"acl": {
"allow_labels": {
"groups": ["foobar"]
}
}
}
}'

使用有效的访问令牌再次向同一路由发送请求:

curl -i "http://127.0.0.1:9080/anything/test" -H "Authorization: Bearer $ACCESS_TOKEN"

你应该会看到 HTTP/1.1 403 Forbidden 响应,表明访问受限。