跳到主要内容

使用 Casbin 在 APISIX 中进行授权

· 阅读需 6 分钟
Rushikesh Tote
Member of Casbin
Yilia Lin
Apache APISIX Committer

简介​

Apache APISIX 可以通过其内置的 authz-casbin 插件在网关处执行 Casbin 授权策略。该插件使用 Lua Casbin,并支持 ACL、RBAC 和 ABAC 等访问控制模型。

本指南在 APISIX 请求路径上设置了一个小型 RBAC 策略。您将验证允许的请求和被拒绝的请求,然后通过插件元数据更新共享策略,而无需更改路由。

Casbin 社区最初在 APISIX Issue #4674 中提出了集成方案,并且 APISIX PR #4710 添加了该插件。

2026 年 8 月刷新

本指南于 2026 年 8 月进行了刷新。示例已在 Apache APISIX 3.17.0 上进行验证。原作者仍保留署名,Yilia Lin 因 2026 年的刷新工作而被添加。

认证边界

Casbin 执行的是授权,而不是认证。此示例仅为了保持测试简单,使用 user 请求头作为主体。在生产环境中,请勿信任由客户端直接提供的身份标头。应由认证层或可信代理建立身份,并在 Casbin 评估请求之前移除或覆盖不可信的值。

前提条件和初始状态​

本指南从一个已经运行的临时 Apache APISIX 3.17.0 实例开始。如果您需要本地实例,请按照 APISIX Docker 部署指南 操作,并将 APISIX 镜像固定为 apache/apisix:3.17.0-debian。

该实例必须具有:

  • 数据平面在 http://127.0.0.1:9080 可用;
  • 位于 http://127.0.0.1:9180 的 Admin API;
  • 启用了内置的 authz-casbin 和 mocking 插件。

你还需要 curl 和 jq。将 admin_key 设置为你的 Admin API 配置的密钥:

export admin_key='<your-admin-api-key>'

在继续之前请替换占位符。确认 Admin API 可访问且插件已启用:

curl --fail-with-body \
"http://127.0.0.1:9180/apisix/admin/plugins/list" \
-H "X-API-KEY: $admin_key" | \
jq -e '(["authz-casbin", "mocking"] - .) | length == 0'

该命令应输出 true。请勿将 Admin API 发布到不受信任的网络, 或在其他环境中复用演示凭据。

定义模型和策略​

该插件评估三个请求值:

  • sub:来自配置请求头的主体;
  • obj:请求 URI 路径;以及
  • act:HTTP 方法。

创建 model.conf:

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)

创建 policy.csv:

p, *, /anything, GET
p, admin, *, *
g, alice, admin

此策略允许任何主体发送 GET /anything。它还分配了 alice 一个 admin 角色,该角色可以使用所有方法访问所有路径。

在插件元数据中存储共享策略​

将文件加载为 JSON 字符串并将其写入 APISIX 插件元数据:

jq -n \
--rawfile model model.conf \
--rawfile policy policy.csv \
'{model: $model, policy: $policy}' | \
curl --fail-with-body \
"http://127.0.0.1:9180/apisix/admin/plugin_metadata/authz-casbin" \
-H "X-API-KEY: $admin_key" \
-H "Content-Type: application/json" \
-X PUT \
--data-binary @-

插件元数据为启用 authz-casbin 但未定义其自身路由局部模型和策略的路由 提供一套模型和策略。

在路由上启用授权​

创建一个路由并告诉插件从 user 头读取主体:

curl --fail-with-body \
"http://127.0.0.1:9180/apisix/admin/routes/casbin-demo" \
-H "X-API-KEY: $admin_key" \
-H "Content-Type: application/json" \
-X PUT \
-d '{
"uri": "/*",
"plugins": {
"authz-casbin": {
"username": "user"
},
"mocking": {
"_meta": {
"priority": 1000
},
"response_status": 200,
"response_example": "{\"message\":\"authorized\"}"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1": 1
}
}
}'

由于该路由仅本地定义了 username 字段,因此它使用来自插件元数据的模型和策略。 如果配置了路由局部的模型和策略,则它们优先于插件元数据。

mocking 插件为允许的请求提供确定性的本地响应,因此 示例不依赖于公共上游服务。其路由局部优先级低于 authz-casbin,这使得授权决策先运行。 因此不会联系不可达的上游服务。这种优先级覆盖 和模拟响应是测试夹具,而非生产环境建议。

验证允许和拒绝决策​

对公共路径的匿名请求被允许:

curl -i http://127.0.0.1:9080/anything

预期状态:

HTTP/1.1 200 OK
{"message":"authorized"}

bob 没有 admin 角色,因此不同路径被拒绝:

curl -i http://127.0.0.1:9080/anything/res -H 'user: bob'

预期结果:

HTTP/1.1 403 Forbidden
{"message":"Access Denied"}

alice 具有 admin 角色,因此相同请求被允许:

curl -i http://127.0.0.1:9080/anything/res -H 'user: alice'

预期状态:

HTTP/1.1 200 OK
{"message":"authorized"}

更新共享策略​

向 policy.csv 添加针对 bob 的直接权限:

p, *, /anything, GET
p, admin, *, *
p, bob, /anything/res, GET
g, alice, admin

再次运行插件元数据命令。引用此元数据的路由使用 更新后的策略而无需更改其路由配置。重复请求:

curl -i http://127.0.0.1:9080/anything/res -H 'user: bob'

现在的预期结果是:

HTTP/1.1 200 OK
{"message":"authorized"}

选择配置范围​

当多个路由应共享一套模型和策略时,使用插件元数据。当路由需要独立的授权 结构时,使用路由局部的模型和策略。有关完整的配置架构和基于文件的替代方案,请参阅 APISIX authz-casbin 插件参考。

清理​

移除测试路由:

curl --fail-with-body \
"http://127.0.0.1:9180/apisix/admin/routes/casbin-demo" \
-H "X-API-KEY: $admin_key" \
-X DELETE

移除共享插件元数据:

curl --fail-with-body \
"http://127.0.0.1:9180/apisix/admin/plugin_metadata/authz-casbin" \
-H "X-API-KEY: $admin_key" \
-X DELETE

Comments are powered by giscus and GitHub Discussions. They load from giscus.app and GitHub only after you click the button below.