1

我在 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()));

想法:

  1. 向联接表添加字段以简化策略,但它违反了正常形式。
  2. 返回用户输入而不是运行 SELECT,但输入可能会被转义,我应该能够运行SELECT命令
  3. 分成两个功能。创建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 命令的另一个策略。如果用户登录,它允许 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()));
4

2 回答 2

0

根据错误信息,您的这部分 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子句添加另一个策略。

于 2021-07-20T05:16:39.417 回答
0

我最终在连接表中添加了一个字段,并用它创建了一个策略。这样,RLS 验证不需要在函数中间创建的行。

于 2021-07-21T02:21:52.960 回答