postgresql - 在 PostGraphile 中处理列级选择授权的最佳实践
问题描述
PostGraphile 不推荐列级 SELECT grants,而是建议
将您的关注点拆分为多个表,并使用一对一的关系功能将它们链接起来。
现在我希望我的users
表有一个role
可以访问role_admin
但不能访问的字段role_consumer
。基于上述建议,我创建了两个表。users
表(在公共模式中)包含两个角色都可以看到的所有字段,并且user_accounts
(在私有模式中)包含role
只有role_admin
必须能够看到的字段。role
字段通过计算列添加到user
GraphQL 类型。
CREATE SCHEMA demo_public;
CREATE SCHEMA demo_private;
/* users table*/
CREATE TABLE demo_public.users (
user_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
);
/* user_accounts */
CREATE TABLE demo_private.user_accounts (
user_id INT PRIMARY KEY REFERENCES demo_public.users (user_id) ON DELETE CASCADE,
role text not null default 'role_consumer',
);
/* role as computed column */
CREATE FUNCTION demo_public.users_role
(
u demo_public.users
)
RETURNS TEXT as $$
<code>
$$ LANGUAGE SQL STRICT STABLE;
现在基本上我有两种药水来设置权限。
1)第一个选项是使用表级安全性。IOW 将表上的选择访问权限授予user_accounts
ONLY role_admin
。
GRANT SELECT ON TABLE demo_private.user_accounts TO role_admin;
GRANT EXECUTE ON FUNCTION demo_public.users_role(demo_public.users) TO role_admin;
ALTER TABLE demo_private.user_accounts ENABLE ROW LEVEL SECURITY;
CREATE POLICY select_any_user_accounts ON demo_private.user_accounts FOR SELECT TO role_admin using (true);
这种方法的问题在于,当role_consumer
运行包含role
字段的查询时
{
me {
firstname
role
}
}
上述查询返回错误。这不好,因为错误会影响隐藏其他同级字段结果的整个结果。
2) 另一个选项是使用除表级别之外的行级别安全性;IOW 在表级别,授予对表的选择访问权限user_accounts
,role_admin
但role_consumer
在行级别仅允许管理员访问user_accounts
.
GRANT USAGE ON SCHEMA demo_private TO role_consumer;
GRANT SELECT ON TABLE demo_private.user_accounts TO role_consumer;
GRANT EXECUTE ON FUNCTION demo_public.users_role(demo_public.users) TO role_consumer;
ALTER TABLE demo_private.user_accounts ENABLE ROW LEVEL SECURITY;
CREATE POLICY select_user_accounts ON demo_private.user_accounts FOR SELECT
USING ('role_admin' = nullif(current_setting('role', true), ''));
现在,如果用户consumer_role
运行上述查询,该role
字段将为空,不会影响其兄弟字段。但是有两个问题:
我们是否应该始终避免错误以防止它们影响兄弟姐妹?
如果是,我们是否应该始终在行级别而不是仅在表级别处理事情?
解决方案
对于选项 1,在查询期间从 PostgreSQL 抛出错误在 PostGraphile 中不是一个好主意,因为我们将整个 GraphQL 树编译为单个 SQL 查询,因此错误会中止整个查询。相反,如果不允许用户查看权限,我会将权限考虑到函数中并简单地返回 null(而不是错误)。一种方法是使用附加WHERE
条款:
CREATE FUNCTION demo_public.users_role (
u demo_public.users
) RETURNS TEXT AS $$
select role
from demo_private.user_accounts
where user_id = u.id
and current_setting('jwt.claims.role') = 'role_admin';
$$ LANGUAGE SQL STABLE;
对于选项 2:这是一个完全有效的解决方案。
我们是否应该始终避免错误以防止它们影响兄弟姐妹?
在 GraphQL 中查询内容时很少会抛出错误 - 通常您会返回 null。可以把它想象成在注销时访问 GitHub 上的私有存储库——它们不会返回表明资源存在的“禁止”错误,而是返回 404 错误,表明它不存在——除非你知道得更好!
如果是,我们是否应该始终在行级别而不是仅在表级别处理事情?
我个人只在 PostGraphile 中使用一个角色,app_visitor
这对于我迄今为止使用 PostGraphile 构建的所有应用程序来说已经足够了。
推荐阅读
- c++ - 将 .exe 文件嵌入到 C++ 程序中?
- pdf - 如何使用 ASP.NET Core MVC 创建自己的 pdf 文件?
- reactjs - 无法将道具传递给材质 ui makeStyles
- pdf - 通过 Itext 5.5.5 签署文档时不符合 PDF/A
- ajax - WordPress - 使用 ajax 和 admin-ajax.php 获取服务器时间
- python-3.x - 熊猫分组并将行转换为多列
- javascript - 为什么一个字符串中的这个数值在其他字符串之间会变成一个字符串?
- reactjs - 只是想找出使用 useReducer + context hooks 的最佳实践
- scala - Spark查询在同类数据上的性能差异
- android - 编辑视图中的文本未垂直对齐