MST

星途 面试题库

面试题:CouchDB HTTP API下复杂场景的查询文档权限控制实现

在一个多租户的CouchDB应用场景中,每个租户有多个用户组,不同用户组有不同的文档查询权限。例如,租户A的财务组可以查询所有财务相关文档,市场组只能查询市场推广相关文档;租户B的类似不同组也有特定文档查询限制。请详细描述如何利用CouchDB的HTTP API设计并实现这种复杂的查询文档权限控制机制,包括安全认证方式的选择和整合等方面。
13.8万 热度难度
数据库CouchDB

知识考点

AI 面试

面试题答案

一键面试

1. 数据库设计

  • 租户区分:为每个租户创建一个独立的数据库,例如 tenant_a_dbtenant_b_db 等。这样从物理层面隔离租户数据,不同租户之间的数据访问不会相互干扰。
  • 用户组与文档关联:在每个租户的数据库中,为文档添加一个字段,比如 group_access,该字段的值是一个数组,包含有权限访问该文档的用户组名称。例如,一个财务文档可能有 {"group_access": ["finance"]},市场推广文档可能有 {"group_access": ["marketing"]}

2. 安全认证方式选择与整合

  • 基本认证(Basic Authentication)
    • 原理:客户端在请求头中发送包含用户名和密码的Base64编码字符串。服务器解码后验证用户名和密码是否匹配。
    • 优点:简单易用,广泛支持。
    • 缺点:用户名和密码在每次请求中都以明文(Base64编码很容易解码)传输,安全性相对较低,不适用于不安全的网络环境。
    • 实现:在CouchDB配置文件(local.ini)中启用基本认证,配置 [httpd] 部分的 WWW-Authenticate 头,例如:
[httpd]
WWW-Authenticate = Basic realm="Restricted Area"
- **用户管理**:可以使用CouchDB内置的用户数据库(`_users` 数据库)来存储用户信息,包括用户名、密码(建议使用哈希值存储)等。使用 `/_users/org.couchdb.user:{username}` 文档格式来创建和管理用户。
  • JSON Web Token(JWT)认证
    • 原理:客户端登录时,服务器验证用户凭据后生成一个JWT,包含用户信息和权限等声明(claims)。客户端在后续请求中携带该JWT,服务器验证JWT的签名和有效性来确认用户身份和权限。
    • 优点:自包含,服务器无需存储用户会话信息,便于分布式部署;可以在JWT中嵌入用户权限信息,方便在请求处理时进行权限验证;传输过程相对安全,因为签名验证可以防止JWT被篡改。
    • 缺点:JWT大小相对较大,会增加请求头的大小;如果JWT泄露,攻击者可以利用它访问系统,因此需要妥善管理JWT的有效期和存储。
    • 实现:在CouchDB前端(如使用Node.js作为中间层)实现JWT生成和验证逻辑。登录时,验证用户信息后生成JWT,例如使用 jsonwebtoken 库:
const jwt = require('jsonwebtoken');
const secret = 'your-secret-key';
const user = { username: 'user1', groups: ['finance'] };
const token = jwt.sign(user, secret, { expiresIn: '1h' });
- 在后续请求中,从请求头中提取JWT并验证:
const jwt = require('jsonwebtoken');
const secret = 'your-secret-key';
const token = req.headers['authorization'].replace('Bearer ', '');
try {
    const decoded = jwt.verify(token, secret);
    // 验证成功,decoded包含用户信息和权限
} catch (err) {
    // 验证失败,返回错误响应
}

3. 利用HTTP API实现查询权限控制

  • 中间层代理:为了实现复杂的权限控制逻辑,建议在客户端和CouchDB之间设置一个中间层(如使用Node.js搭建的服务器)。这个中间层负责接收客户端的请求,进行安全认证(如验证JWT),并根据用户所属的用户组来构建符合权限的CouchDB查询请求。
  • 查询构建
    • 基于视图查询:在每个租户的数据库中创建视图(view)。例如,对于财务组的查询,可以创建一个视图,其 map 函数如下:
function (doc) {
    if (doc.group_access.indexOf('finance')!== -1) {
        emit(doc._id, doc);
    }
}
- 中间层接收到客户端查询请求时,首先解析JWT获取用户所属的用户组,然后根据用户组选择对应的视图进行查询。例如,如果用户属于财务组,中间层构建如下的CouchDB查询请求:
GET /tenant_a_db/_design/finance_view/_view/finance_docs
- **使用选择器查询(Selector Queries)**:CouchDB 2.0+ 支持选择器查询。可以利用 `group_access` 字段构建选择器。例如,对于市场组的查询,中间层构建如下请求:
POST /tenant_a_db/_find
{
    "selector": {
        "group_access": {
            "$in": ["marketing"]
        }
    }
}

中间层在构建请求时,根据用户组动态生成选择器内容,确保只有符合权限的文档被查询出来并返回给客户端。

通过上述方法,可以利用CouchDB的HTTP API实现多租户场景下复杂的文档查询权限控制机制,并整合合适的安全认证方式。