【问题标题】:Postgres row level security insert returningPostgres 行级安全插入返回
【发布时间】:2022-01-24 17:26:24
【问题描述】:

鉴于我的架构中的以下 sn-p:

create table users (
  id   serial primary key,
  name text not null
);

create table user_groups (
  id   serial primary key,
  name text not null
);

create table user_user_group (
  user_id       integer not null references users(id),
  user_group_id integer not null references user_groups(id)
);

grant all on users to staff;
grant all on user_groups to staff;
grant all on user_user_group to staff;

create function can_access_user_group(id integer) returns boolean as $$
  select exists(
    select 1
    from user_user_group
    where user_group_id = id
    and user_id = current_user_id()
  );
$$ language sql stable security invoker;

create function can_access_user(id integer) returns boolean as $$
  select exists(
    select 1
    from user_user_group
    where user_id = id
    and can_access_user_group(user_group_id)
  );
$$ language sql stable security invoker;

alter table users enable row level security;
create policy staff_users_policy
  on users
  to staff
  using (
    can_access_user(id)
  );

请假设staff 角色和current_user_id() 功能已经过测试并且工作正常。我希望允许“员工”角色通过user_user_group在他们可以访问的用户组中创建用户。以下语句使staff_users_policy 失败:

begin;
set local role staff;

with new_user as (
  insert into users (
    name
  ) values (
    'Some name'
  )
  returning id
) 
insert into user_user_group (
  user_id,
  user_group_id
) 
select 
  new_user.id, 
  1 as user_group_id
from new_user;
          
commit;

我可以像这样添加staff_insert_users_policy

create policy staff_insert_users_policy
  on users
  for insert
  to staff
  with check (
    true
  );

这允许我插入用户,但在 returning id 上失败,我需要新的用户 ID 才能将行添加到 user_user_group 表中。

我明白它为什么会失败,但从概念上讲,我该如何避免这个问题?我可以为此创建一个“定义者”函数,或者一个具有自己策略的新角色,但我希望有一个更直接的方法。

【问题讨论】:

  • 您找到解决此问题的方法了吗?我也有。
  • 不,抱歉。我最终使用了定义函数和手动检查。
  • 好的。我最终做了同样的事情。
  • @AtaiasReis 你能举个例子吗?
  • @Akrambek 我更改了项目,但我没有示例了。但是,您可以查看 PostGraphile 的文档:graphile.org/postgraphile/postgresql-schema-design/…。寻找“定义者”,他们根据我的记忆很好地解释了它。

标签: postgresql row-level-security


【解决方案1】:

我也刚刚解决了这个问题,并通过在插入之前生成 uuid 来解决它:

create or replace function insert_review_with_reviewer(
  v_review_input public.review,
  v_reviewer_input public.reviewer
)
  returns void
  language plpgsql
  security invoker
as
$$
declare
  v_review_id uuid := gen_random_uuid();
begin
  insert into public.review
  (id,
   organisation_id,
   review_channel_id,
   external_id,
   star_rating,
   comment)
  values (v_review_id,
          v_review_input.organisation_id,
          v_review_input.review_channel_id,
          v_review_input.external_id,
          v_review_input.star_rating,
          v_review_input.comment);

  insert into public.reviewer
    (organisation_id, profile_photo_url, display_name, is_anonymous, review_id)
    values (v_reviewer_input.organisation_id, v_reviewer_input.profile_photo_url, v_reviewer_input.display_name,
            v_reviewer_input.is_anonymous, v_review_id);
  end if;
end
$$;

【讨论】:

  • 谢谢,这是避免问题的好方法,我很生气我当时没有想到!
猜你喜欢
  • 1970-01-01
  • 2019-05-10
  • 1970-01-01
  • 2019-08-07
  • 2018-10-07
  • 2017-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多