跳转至主要内容

在 APISIX 中使用 Casbin 做授权

· 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 上验证。仍署名 2021 年的原作者,并新增 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 访问;
  • Admin API 可以通过 http://127.0.0.1:9180 访问;
  • 已启用内置的 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.