mongodb的rbac靠db.createrole()和db.createuser()动态生效,权限严格绑定认证库与resource中显式声明的db+collection组合,非文档设计;跨库需多privileges条目或明确分配多{role,db}。

直接说结论:MongoDB 的 RBAC 不是靠“写文档”实现的,而是靠 db.createRole()、db.createUser() 和严格匹配的资源范围(db + collection)动态生效的。所谓“设计文档”,其实是把权限策略翻译成可执行的 Shell 命令和角色定义,不是产出 Word 或 Markdown 文档。
角色定义必须显式声明每个 db + collection 组合
常见错误是以为一个角色能自动覆盖“同名集合在不同库”的权限。比如给 appReader 授予 { db: "myapp", collection: "orders" } 的 find 权限,但应用连的是 test 库并执行 db.orders.find() —— 这会直接报 Unauthorized。
- 权限只对当前
use的数据库生效;db.getSiblingDB("myapp").orders.find()不触发myapp.orders的权限检查 - 想让一个角色同时读 A 库、写 B 库,必须在同一个
db.createRole()调用里写两条privileges条目:{ resource: { db: "A", collection: "x" }, actions: ["find"] }和{ resource: { db: "B", collection: "y" }, actions: ["insert"] } - 角色必须在
admin库创建,否则无法被跨库引用(除非用户也在admin认证)
用户认证库决定角色生效范围
用户在哪一个库执行 db.auth(),就只加载该库下分配的角色 —— 即使你给用户分配了 { role: "read", db: "otherdb" },但如果 db.auth({ user: "u", db: "myapp" }),那么 otherdb 的角色完全不加载。
- 验证当前会话实际拥有的角色和权限范围,运行:
db.runCommand({ connectionStatus: 1 }),看authInfo.roles和authInfo.privileges - 跨库权限唯一安全做法:在用户创建时,明确指定多个
{ role: "...", db: "..." },且每个db都真实存在、已初始化 - 不要依赖
readAnyDatabase等高危内置角色,它绕过所有库级隔离,审计时会被直接否决
内置角色权限范围极易误判
read 和 readWrite 看似通用,其实只对“当前认证库”有效。很多人以为分配了 { role: "read", db: "logs" } 就能在任意库执行日志查询,结果发现连 logs 库都进不去。
-
dbAdminAnyDatabase、userAdminAnyDatabase等 “AnyDatabase” 角色**只在admin库创建才生效**,在其他库创建等于无效 -
dbOwner≠root:dbOwner仅限单库全权,root是admin库专属,覆盖整个集群 - 测试时务必用真实连接串模拟应用行为:比如 Spring Boot 的
spring.data.mongodb.uri=mongodb://u:p@h:27017/myapp,认证库是myapp,不是admin
真正容易被忽略的点在于:权限检查发生在命令解析阶段,而不是执行阶段。也就是说,db.orders.find() 是否被允许,取决于当前 use 的库是否匹配角色中定义的 resource.db,跟实际操作哪个集合无关 —— 即使集合名一致,库不对,照样拒绝。











