面试题答案
一键面试思路
- 租户识别:在HTTP请求中确定租户身份,常见方式是通过请求头、子域名或URL路径参数。
- 角色识别:类似地,识别请求用户在该租户内的角色,可基于身份验证机制或额外的请求头信息。
- 视图定制:设计CouchDB视图时,将租户ID作为关键部分,使得可以按租户过滤数据。对于不同角色,可能需要设计不同视图或在同一视图中通过附加逻辑区分。
- 安全层:在应用程序的HTTP API层实现安全检查,根据识别出的租户和角色决定是否允许查询。
关键步骤
- 租户ID注入:在数据写入CouchDB时,确保每条文档都包含租户ID字段。例如,使用如下Node.js代码(假设使用
cradle
库操作CouchDB):
var cradle = require('cradle');
var db = new(cradle.Connection)('localhost', 5984).database('your_database');
var newDoc = {
tenant_id: 'tenant123',
// 其他文档数据
};
db.save(newDoc, function (err, res) {
if (!err) {
console.log(res);
}
});
- 视图设计:创建基于租户ID的视图。例如,在CouchDB的
_design
文档中定义如下Map函数:
function (doc) {
if (doc.tenant_id) {
emit(doc.tenant_id, doc);
}
}
这样就可以通过?key="tenant123"
的方式查询特定租户的数据。
3. 租户识别中间件:在应用程序的HTTP服务器(如Express.js)中添加中间件识别租户ID:
app.use(function(req, res, next) {
// 假设租户ID在请求头中
var tenantId = req.headers['x - tenant - id'];
if (!tenantId) {
return res.status(400).send('Missing tenant ID');
}
req.tenantId = tenantId;
next();
});
- 角色识别与权限检查:同样在中间件中识别角色并进行权限检查。假设角色信息从身份验证服务获取并放在请求头:
app.use(function(req, res, next) {
var role = req.headers['x - user - role'];
var tenantId = req.tenantId;
// 示例:只有管理员能查询所有文档,普通用户只能查询自己创建的
if (role === 'admin') {
next();
} else if (role === 'user') {
// 假设文档有creator字段,且与租户ID关联
req.query = req.query || {};
req.query.startkey = [tenantId, req.user_id];
req.query.endkey = [tenantId, req.user_id, {}];
next();
} else {
return res.status(403).send('Forbidden');
}
});
- API代理:通过应用程序的API代理对CouchDB的视图查询,确保所有查询都经过上述安全检查。例如,使用
request
库在Express.js中代理查询:
app.get('/api/view', function(req, res) {
var queryUrl = 'http://localhost:5984/your_database/_design/your_design_doc/_view/your_view?' + querystring.stringify(req.query);
request(queryUrl).pipe(res);
});