使用Loopback中的访问控制列表来限制对表记录的访问

时间:2016-09-23 20:14:01

标签: node.js acl loopbackjs data-access-layer

我们正在为Node.js RESTful API使用Loopback。我们想知道我们是否可以利用模型上的先天访问控制列表属性来限制对特定用户的某些记录/对象的访问。我希望这是可能的,我们不需要实现自己的逻辑。假设我们有两个这样的表(在Postgres中):

contracts
| id | name | manager_id |
|----|------|-------------|
| 1  | a    | 4           |
| 2  | b    | 5           |
| 3  | c    | 6           |

contract_managers
| id | name |
|----|------|
| 4  | e    |
| 5  | f    |
| 6  | g    |

我们想要的是对合同表实施低级访问控制 - 限制用户只访问某些记录。鉴于文档,目前尚不清楚我们是否可以单独使用ACL来限制对特定记录的访问。

如果有人登录我们的应用程序并且他们是contract_manager,我们希望他们只能从contract表中读取manager_id是登录用户ID的记录。例如,如果我登录并且我的用户id = 4,那么我就是一个contract_manager,我应该只能读取manager_id = 4的合同表。

有没有办法用ACL实现这个简单的逻辑?或者我们是否需要创建自定义逻辑?

1 个答案:

答案 0 :(得分:1)

如果您定义custom role resolver,然后添加具有限制特定访问权限的ACL条目,则可以执行此操作。

Role.registerResolver('$manager', function (role, ctx, callback) {
  if (ctx.modelName === 'Contract') {
    app.models.Contract.count({
      id: ctx.modelId,

      // I'm assuming the ContractManager model extends User model.
      // If instead there's a relation between ContractManager and User,
      // Use include and scopes to filter it.
      managerId: ctx.accessToken.userId,
    }, function(err, count) {
      if (err) {
        callback(err);
      } else if (count) {
        callback();
      } else {
        callback(new Error('Not Manager'));
      }
    });
  } else if (ctx.modelName === 'ContractManager') {

    // Again making the same assumption about ContractManager. Chnage
    // accordingly.
    if (ctx.accessToken.userId === ctx.modelId) {
      callback();
    } else {
      process.nextTick(() => callback(new Error('Not Manager')));
    }
  } else {
    process.nextTick(() => callback(new Error('Only for ContractManager or Contract')));
  }
}

然后你必须添加这个acl(随意使它更具体):

{
  "accessType": "*",
  "principalType": "ROLE",
  "principalId": "$manager",
  "permission": "ALLOW",
  "property": "*",
  "model": "*"
}

现在请注意,此角色解析器仅适用于原型方法(即findById,/api/Contract/{id}),而不适用于静态方法(即find,/api/Contract),因为我们使用的是ctx.modelId,它是仅适用于原型方法调用。