如何仅通过 _security 对象把数据库的读写权限授予“reader”与“writer”两个角色?
解读
国内面试中,这道题考察的是“能否在不借助额外设计文档、不改动默认安全处理器的前提下,仅用 _security 对象完成最小权限闭环”。
很多候选人会下意识回答“在 validate_doc_update 里做判断”或“再加一个设计文档”,这都会被判为跑题。
正确姿势是:把 _security 当成数据库级 ACL,一次性声明“谁可以读、谁可以写”,不引入任何其他逻辑。
面试官常追问:
- 如果同时出现 names 与 roles,优先级如何?
- 匿名用户是否还能写?
- 该配置在集群里多久可见?
回答必须围绕 _security 的原子性、即时性、排他性展开。
知识点
- _security 是 CouchDB 的数据库级安全文档,路径为
/{db}/_security,不在 _users 系统表里。 - 合法顶层字段只有两个:admins 与 members,各自包含 names 数组与 roles 数组。
- members.roles 决定“读+写”权限;admins.roles 决定“读+写+删+改安全文档”的超级权限。
- 若未在 _security 中显式声明,默认所有人拥有读写权限(国内公有云通常已关闭该默认)。
- 修改 _security 不需要重启节点,在集群中通过内部 RPC 秒级同步。
- 验证顺序:先匹配 admins(任意命中立即放行),再匹配 members;都不命中则拒绝。
答案
向目标数据库发送一次 PUT 请求,只保留 members 字段,显式写入角色列表即可:
PUT /{db}/_security
Content-Type: application/json
{
"members": {
"roles": ["reader","writer"]
}
}
返回 200 即生效。
解释要点:
- 未声明 admins,因此管理员只能由 server admin(.ini 里 [admins] 段落)充当,防止普通用户提权。
- 未写 names 数组,避免硬编码账号,符合“角色而非个人”的国内审计规范。
- 此时:
- 拥有 reader 或 writer 角色的用户可读取所有文档;
- 拥有 reader 或 writer 角色的用户可写入所有文档;
- 匿名用户或没有这两个角色的账号任何操作都会收到 401。
- 若后续需要回收权限,只需从 roles 数组中移除对应角色并再次 PUT,无需改代码、无需重建索引。
拓展思考
- 国内等保 2.0 要求“三权分立”,可把角色拆细:
reader → 只读审计角色;writer → 业务写角色;再建一个 dba 角色放入 admins.roles,实现“读写删”与“改安全”分离。 - 若使用 CouchDB 3.x+,可配合 _partitioned 数据库与 db-per-user 模式,把 _security 的 roles 与 JWT 中的
rolesclaim 映射,实现微服务场景下的多租户隔离,而无需写一行 validate 函数。 - 注意 roles 是数组完全匹配,不支持通配符;如果业务线很多,建议角色命名加前缀,如
app1_reader、app2_writer,避免跨业务越权。 - 面试加分点:提到写 _security 需要 server admin 身份,普通 db member 无法篡改;同时建议打开
[couch_httpd_auth] require_valid_user = true,关闭匿名访问,满足国内公有云合规扫描。