mongodb的rbac不依赖自定义collection存角色/权限实现鉴权,因服务端仅读取admin.system.roles和admin.system.users系统集合,权限校验在命令执行前由内核privilege::check()硬编码完成,业务库中sys_role等表完全被忽略。

MongoDB 的 RBAC 不靠“文档模型”实现鉴权,所谓“设计文档模型”是常见误解——权限检查发生在连接层与命令执行前,由 db.createRole() 定义的特权集合 + db.createUser() 分配的角色共同决定,不依赖任何用户自定义集合或 JSON 文档结构。
为什么不能用 collection 存角色/权限做实时鉴权
MongoDB 的授权系统在服务端内核中硬编码实现,所有权限校验走的是 Privilege::check() 路径,它只读取 admin.system.roles 和 admin.system.users 这两个系统集合(且仅在认证时加载),完全忽略你业务库里的 sys_role、sys_permission 等自定义表。哪怕你在应用里查出用户有 “order:write” 权限,执行 db.orders.insertOne() 时仍会因缺少 insert 动作而报 Unauthorized。
- 应用层模拟 RBAC(如查
sys_user_role表再做 if 判断)无法防止直接连 MongoDB Shell 的越权操作 - 所有
find/update命令都先过服务端权限检查,你的业务代码根本没机会运行 - 字段级、行级控制在原生 MongoDB 中不存在(4.4+ 的
document validation是写入校验,非读权限)
真正影响鉴权速度的关键配置项
鉴权性能瓶颈不在“查哪张表”,而在角色加载路径和资源匹配粒度。MongoDB 每次命令执行前需展开角色继承链、合并所有 privileges、逐条匹配当前操作的 {db, collection} 是否在 resource 范围内。以下参数直接影响速度:
-
authInfo.roles数量:单个用户分配超过 5 个角色会明显拖慢connectionStatus返回时间(实测 >200ms) - privileges 中
resource: { db: "", collection: "" }的通配使用:用collection: ""代替具体名会导致全库扫描匹配 - 角色创建库不是
admin:非 admin 库创建的角色无法被跨库引用,强制你在每个库重复建角色,增加加载开销 - 启用了
authenticationRestrictions:每次连接都要查 IP 白名单,网络延迟敏感
如果非要存权限策略到 MongoDB,该放哪、怎么用
可以存,但只能作为策略源(source of truth),不能替代原生 RBAC。典型做法是把权限规则导出为可执行脚本,而非运行时查询:
- 用
sys_role集合存角色元数据(如描述、生效时间),但不参与鉴权流程 - 写一个同步脚本,监听
sys_role变更,自动调用db.createRole()更新admin.system.roles - 用户创建后,脚本再调用
db.grantRolesToUser()同步分配,避免人工漏配 - 禁止前端或业务代码读
sys_role做权限判断——它和实际生效的角色可能有分钟级延迟
这种模式下,sys_role 本质是配置管理后台的数据库,不是鉴权引擎的一部分。
跨库权限最容易踩的坑
90% 的 Unauthorized 报错源于认证库与目标库不一致。关键事实:
- 用户必须在
admin库创建,否则db: "otherdb"的角色分配无效 -
db.auth({ user: "u", db: "myapp" })只加载myapp库下分配的角色,即使你写了{ role: "read", db: "logs" }也白搭 -
db.getSiblingDB("logs").orders.find()不触发logs.orders的权限检查,它走的是当前会话认证库(myapp)的权限集 - 验证当前有效权限,唯一可靠方式是
db.runCommand({ connectionStatus: 1 }),看authInfo.privileges里有没有你要的操作
真正安全的跨库方案只有两种:所有操作切到对应库再执行(use logs),或在 admin 库给用户分配多个 { role, db } 对,且每个 db 都真实存在。











