MST

星途 面试题库

面试题:如何定制CouchDB HTTP API查询视图安全策略以满足复杂业务场景

假设你正在开发一个多租户的应用程序,不同租户有不同的数据访问权限。使用CouchDB作为后端数据库,需要通过定制HTTP API查询视图的安全策略,确保每个租户只能访问自己的数据,且不同租户角色(如管理员、普通用户)具有不同的查询权限。请描述你实现这一复杂安全策略的详细思路与关键步骤。
35.4万 热度难度
数据库CouchDB

知识考点

AI 面试

面试题答案

一键面试

思路

  1. 租户识别:在HTTP请求中确定租户身份,常见方式是通过请求头、子域名或URL路径参数。
  2. 角色识别:类似地,识别请求用户在该租户内的角色,可基于身份验证机制或额外的请求头信息。
  3. 视图定制:设计CouchDB视图时,将租户ID作为关键部分,使得可以按租户过滤数据。对于不同角色,可能需要设计不同视图或在同一视图中通过附加逻辑区分。
  4. 安全层:在应用程序的HTTP API层实现安全检查,根据识别出的租户和角色决定是否允许查询。

关键步骤

  1. 租户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);
    }
});
  1. 视图设计:创建基于租户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();
});
  1. 角色识别与权限检查:同样在中间件中识别角色并进行权限检查。假设角色信息从身份验证服务获取并放在请求头:
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');
    }
});
  1. 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);
});