面试题答案
一键面试1. 数据库设计
- 租户区分:为每个租户创建一个独立的数据库,例如
tenant_a_db
,tenant_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
函数如下:
- 基于视图查询:在每个租户的数据库中创建视图(view)。例如,对于财务组的查询,可以创建一个视图,其
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实现多租户场景下复杂的文档查询权限控制机制,并整合合适的安全认证方式。