我试图在node.js应用程序中实现基于角色的访问控制,使用bookshelf.js作为Postgresql的ORM。我有以下架构:

USERS <- USERS_ROLES -> ROLES <- ROLES_RIGHTS -> RIGHTS

我希望能够获得用户拥有的所有权限。在sql中,我只需要这样做:
SELECT rights.*
FROM rights
INNER JOIN roles_rights ON roles_rights.right_id=rights.id
INNER JOIN users_roles ON users_roles.role_id = roles_rights.role_id
WHERE users_roles.user_id=1
GROUP BY rights.id

由于对Bookshelf.js还比较陌生,我很难弄清楚如何建立这种关系。这是我的第一次尝试:
const User = bookshelf.Model.extend({

  tableName: 'users',

  roles: function() {
    return this.belongsToMany(Role, 'users_roles', 'user_id', 'role_id')
  },

  rights: function() {
    return this.belongsToMany(Right, 'users_roles', 'user_id', 'role_id')
      .query(qb => qb
        .innerJoin('roles_rights', 'roles_rights.right_id', 'rights.id')
      )
  }

})

const Role = bookshelf.Model.extend({

  tableName: 'roles',

  rights: function() {
    return this.belongsToMany(Right, 'roles_rights', 'role_id', 'right_id')
  },

  users: function() {
    return this.belongsToMany(User, 'users_roles', 'user_id', 'role_id')
  }

})

const Right = bookshelf.Model.extend({

  tableName: 'rights',

  roles: function() {
    return this.belongsToMany(Role, 'users_roles', 'user_id', 'role_id')
  }

})

它不起作用。。。:-(
最后,我想让这个查询工作:
User.where({ id: req.user.get('id') })
  .fetch({ withRelated: ['rights'] })
  .then(user => {
    ...
  })
})

任何帮助都将不胜感激!

最佳答案

在同一个问题上挣扎了一段时间之后,这是我最接近可用解决方案的一个。
不需要对您描述的模型进行任何修改(除了从rights模型中删除User关系外),您可以执行以下操作:

User.where({ id: req.user.get('id') })
  .fetch({ withRelated: ['roles.rights'] })
  .then(user => {
    console.log(JSON.stringify(user));
  })
})

我发现这对我的用例更好,因为我将始终拥有可用的用户角色和其中的角色权限。
像这样的:
{
  id: 12
  roles: [
    {
      id: 21,
      rights: [
        {
          id: 11,
          name: 'DELETE'
        }
      ]
    }
  ]
}

如果您确实需要用户从所有角色中组合的所有权限,则可以使用Bookshelf的virtual s插件创建一个虚拟行。
const User = bookshelf.Model.extend({

  tableName: 'users',

  roles: function() {
    return this.belongsToMany(Role, 'users_roles', 'user_id', 'role_id')
  },

  virtuals: {
    rights: {
      get: function () {
        const rightsIds = new Set();
        return this.related('roles').reduce((rights, group) => {
          return group.related('rights').reduce((rights, right) => {
            if (!rightsIds.has(right.id)) {
              rightsIds.add(right.id);
              rights.push(right);
            }
            return rights;
          }, rights);
        }, []);
      }
    }
  },
});

像这样使用:
User.where({ id: req.user.get('id') })
  .fetch({ withRelated: ['roles.rights'] })
  .then(user => {
    console.log(JSON.stringify(user.get('rights'));
  })
})

初始化书架时必须启用virtuals插件:
bookshelf.plugin(['virtuals']);

这不是最优雅的解决方案,但如果你想做的一切与书架,这是它。每当书架让我失望时(这种情况经常发生),我就使用knex

09-12 02:08