问题描述
我在 Postgres 函数上违反了 RLS 政策。我相信这是因为该策略依赖于在函数中创建的行。 SELECT
命令在函数中运行。新行不可用,因为它们仍在事务中。
功能如下:
CREATE FUNCTION public.create_message(organization_id int,content text,tags Int[])
RETURNS setof public.message
AS $$
-- insert message,return PK
WITH moved_rows AS (
INSERT INTO public.message (organization_id,content)
VALUES($1,$2)
RETURNING *
),-- many to many relation
moved_tags AS (
INSERT INTO public.message_tag (message_id,tag_id)
SELECT moved_rows.id,tagInput.tag_id
FROM moved_rows,UNnesT($3) as tagInput(tag_id)
RETURNING *
)
SELECT moved_rows.* FROM moved_rows LEFT JOIN moved_tags ON moved_rows.id = moved_tags.message_id
$$ LANGUAGE sql VOLATILE STRICT;
这是政策:
CREATE POLICY select_if_organization
on message_tag
for select
USING ( message_id IN (
SELECT message.id
FROM message
INNER JOIN organization_user ON (organization_user.organization_id = message.organization_id)
INNER JOIN sessions ON (sessions.user_id = organization_user.user_id)
WHERE sessions.session_token = current_user_id()));
想法:
- 在连接表中添加一个字段以简化策略,但它违反了正常形式。
- 返回用户输入而不是运行 SELECT,但输入可能会被转义,我应该能够运行
SELECT
命令 - 分为两个功能。创建
message
行,然后添加message_tag
。我正在运行 postgraphile,所以有两个突变。我在两者之间设置了外键关系。我不知道 graphile 是否会自动做到这一点。
错误信息:
ERROR: new row violates row-level security policy for table "message_tag"
CONTEXT: sql function "create_message" statement 1
我在运行该函数时收到错误消息。我希望函数成功运行,在 message
表中插入一行,并将输入数组转换为 message_tag
表的行,其中 message_tag.message_id=message.id
,最后插入的 id。我需要制定一项政策,以便来自该加入关系的用户只能看到他们自己组织的 message_tag
行。
这是关于 INSERT 命令的另一个策略。如果用户已登录,则允许插入:
create policy insert_message_tag_if_author
on message_tag
for insert
with check (EXISTS (SELECT * FROM sessions WHERE sessions.session_token = current_user_id()));
解决方法
根据错误提示,你的这部分SQL语句导致错误:
INSERT INTO public.message_tag (message_id,tag_id)
SELECT moved_rows.id,tagInput.tag_id
FROM moved_rows,UNNEST($3) as tagInput(tag_id)
RETURNING *
您需要使用适当的 FOR INSERT
子句添加另一个策略 WITH CHECK
。
我最终在连接表中添加了一个字段,并用它创建了一个策略。这样,RLS 验证不需要在函数中间创建的行。