Postgresql 如何使用Postgraphile或替代方案在Postgres中实现复杂的基于权限的数据访问

Postgresql 如何使用Postgraphile或替代方案在Postgres中实现复杂的基于权限的数据访问,postgresql,graphql,prisma,hasura,postgraphile,Postgresql,Graphql,Prisma,Hasura,Postgraphile,对于一个新项目,我们目前正在设计一个数据库和一个API来访问它。我们已经确定我们将对数据库使用PostgresQL,并希望通过GraphQLAPI访问它 为了便于维护,我们研究了客户端/API/数据库之间的几个中介,主要是Prisma、PostGraphile和Hasura。PostGraphile脱颖而出,因为它易于使用,并且重点处理“数据库”中的内容,而不是后端代码中的内容。然而,在弄清楚如何实现这一点时,我们遇到了一些问题 请允许我进一步介绍我们迄今为止的设计: 临时数据库设计: 用户

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

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

请允许我进一步介绍我们迄今为止的设计:


临时数据库设计:

  • 用户
    表格
  • 角色
    表格:
  • u_g_r
    表格:一个用户可以是多个组的一部分,并且在每个组中可以有多个角色。此表表示
    用户
    角色
    的外键,因为几乎所有组合中都可能存在多对多关系
数据权限:

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

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;
  • 第三级:你自己,只有绝对必要的人,如客户经理
  • 级别2:仅X、Y等组中的人员
  • 第一级:每个人
如果可以为各种类型的数据设置这一级别,例如为您的电话号码授予2级权限,但仅为您的物理地址授予1级权限,那就太棒了。 因此,这些级别(1、2、3)将伴随数据库中的数据,例如
phone\u number
phone\u number\u access\u level
。然后,在
u\u g\r
连接表中,
用户
/
/
角色
的每个组合都会附加一个允许的级别,该级别必须高于相关数据的要求级别。因此,如果您的
角色
允许访问级别2上的数据,您将能够查看级别1和2上的数据,但不能查看级别3上的数据


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

你建议我们做什么?请告诉我是否有我们错过的选项,或者是否有其他更适合我们的选项


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

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

您可能无法使用列权限,因为这些权限只能允许或拒绝对整个列的访问,而不考虑“拥有”某个表行的人

因此,视图可能可以执行您想要的操作,例如:

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\u barrier
确保任何人都不能使用具有副作用的function来破坏安全性,
check\u option
确定任何人都不能
插入自己看不见的行


如果定义
而不是
触发器,则可以允许对视图执行DML操作。

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

当我上周回到这个话题时,一个更干净的解决方案(可以说)出现在我的脑海中。我现在不再像这样使用自定义视图,而是使用带有敏感数据的单独表,用外键链接它们,并在这些行上启用行级安全性


我还没有做过任何基准测试,但应该会更快,因为这些数据并不总是需要的。它至少用大量的样板文件保存了复杂的视图

非常有趣!我一定会调查的!Hasura的权限系统将字段和行级安全性考虑在一起,也就是说,您可以在具有1)ReLe1的表上拥有权限,这可以访问FeldA、FeldB和Load条件1和2)RoLe2,这可以访问FeldC、Feldd和Lead条件2。见: