1

对于一个新项目,我们目前正在设计一个数据库和一个 API 来访问它。我们已经确定我们将使用 PostgresQL 作为数据库,并希望通过 GraphQL API 访问它。

为了简化可维护性,我们研究了客户端/API/数据库之间的几个中介,主要是 Prisma、PostGraphile 和 Hasura。PostGraphile 脱颖而出,因为它易于使用,并且专注于处理“在数据库中”而不是在后端代码中的内容。但是,在弄清楚如何实现这一点时,我们遇到了问题。

请允许我扩展我们迄今为止的设计:


临时数据库设计:

  • users桌子
  • groups桌子
  • roles桌子:
  • u_g_r表:一个用户可以是多个组的一部分,并且每个组可以有多个角色。该表表示和的外键users,因为多对多关系几乎可以存在于所有组合中。groupsroles

数据权限:

我们希望用户通过几个步骤授予其他人访问其个人数据的权限,最好是针对每个组。例如:

  • 3级:你自己,只有绝对必要的人,比如客户经理
  • 2级:只有X、Y等组的人
  • 1级:所有人

如果可以为各种类型的数据设置此项,那就太棒了,例如为您的电话号码授予第 2 级,但为您的实际地址授予第 1 级。因此,这些级别(1、2、3)将伴随数据库中的数据,例如phone_numberphone_number_access_level。然后,在联结表中,//u_g_r的每个组合都会附加一个允许的级别,该级别必须高于相关数据所需的级别。因此,如果您允许访问级别 2 上的数据,您将能够查看级别 1 和级别 2 上的数据,但不能查看级别 3。usergrouprolerole


Postgres 允许列和行级别的安全性,让用户访问某些数据。PostGraphile wiki 详细介绍了(此处此处)如何使用 JWT 声明而不是 PostGres 角色来完成这项工作。当我们想要实现上述功能时,我们的问题就来了。似乎我们想要一种不存在的“现场级安全”,但我无法想象其他人没有遇到同样的问题。

你会建议我们做什么?请让我知道是否有我们遗漏的选项,或者是否有其他更适合我们的选项!

在数据库之外,在后端代码中实现这一点可能是最简单的方法,但它极大地影响了我们的可维护性,因为像 PostGraphile 这样的东西对我们来说主要的奢侈是消除了我们自己编写 GraphQL 模式和解析器的需要。

4

2 回答 2

0

根据 Laurenz Albe 的回答,我为各种列创建了一个巨大的视图。它确实有效,即使有数千个模拟数据条目,它仍然相对较快。

当我上周回到它时,我想到了一个更清洁的解决方案(可以说)。我现在不是使用像这样的自定义视图,而是使用带有敏感数据的单独表,将它们与外键链接并在这些行上启用行级别安全性。

我没有做任何基准测试,但它应该更快,因为无论如何并不总是要求这些数据。它至少可以节省大量样板文件的复杂视图!

于 2021-01-19T09:29:22.607 回答
0

您似乎希望所有用户都能看到所有表格行,但只能看到某些列。

您可能无法使用列权限,因为这些权限只能允许或拒绝对整个列的访问,并且不尊重谁“拥有”某个表行。

所以也许视图可以做你想做的事,例如:

CREATE VIEW users_view
WITH (security_barrier = true, check_option = local) AS
SELECT /* accessible to everyone */
       username,
       /* accessible only to certain groups */
       CASE WHEN pg_has_role('x', 'USAGE') OR pg_has_role('y', 'USAGE')
            THEN level2_col
            ELSE NULL
       END AS level2_col,
       /* accessible only to admins and owner */
       CASE WHEN username = current_user OR pg_has_role('admin', 'USAGE')
            THEN level3_col
            ELSE NULL
       END AS level3_col
FROM users;

security_barrier确保没有人可以使用具有副作用的函数来破坏安全性,并check_option确定没有人可以INSERT使用自己不可见的行。

如果定义INSTEAD OF触发器,则可以允许对视图进行 DML 操作。

于 2020-10-20T11:42:54.137 回答