В Postgraphile используйте разрешения для отношений "многие-ко-многим"

Как подойти к определению расширенных разрешений и авторизации для отношений «многие ко многим» с помощью Postgraphile?

Представьте, что у меня есть отношения «многие ко многим» (любезно заимствованные из официального документы и настроены с упрощенными разрешениями):

create table post (
  id serial primary key,
  headline text,
  body text,
  summary text
);
create table author (
  id serial primary key,
  name text
);

create type post_permission as enum (
  'owner', -- assume owner can change `headline`, `summary` and `body` of a post
  'editor' -- assume editor can modify `summary` of a post
);
create table post_author (
  post_id integer references post,
  author_id integer references author,
  permission post_permission,
  primary key (post_id, author_id)
);

Я могу создать политику безопасности на уровне строк, например:

create policy update_post on post for update to app_user using (
  EXISTS(
    SELECT 1
    FROM post_author as pa
    WHERE pa.post_id = post.id 
      AND pa.author_id = app_hidden.current_user_id()
      AND pa.permission = 'owner'
  )
);

-- Assume `app_hidden.current_user_id()` returns a logged in user id

Но поскольку я недавно преобразовал MySQL в PostgreSQL, я пытаюсь проверить, могу ли я выполнить проверку политики pa.permission, описанную выше, в отношении попытки изменения и разрешить только permission = owner обновлять все поля сообщения, тогда как пользователь с permission = editor может просто обновить summary.

Я знаю, что это часто выполняется на уровне приложения, а не в базе данных, но решил, что сначала увижу, что возможно.

Спасибо!

См. Также связанную тему здесь.


person Cameron    schedule 12.02.2021    source источник
comment
Ваша первая схема postgres выглядит нормально. Что с этим не так? Какую схему GraphQL вы хотите реализовать, чего не можете?   -  person Bergi    schedule 12.02.2021
comment
@Bergi Я изучаю политики мутации с помощью RLS, я обновил свой вопрос, добавив более подробные сведения и некоторый дополнительный контекст кода.   -  person Cameron    schedule 14.02.2021
comment
Придется вас разочаровать: политики безопасности на уровне строк могут ограничивать обновления только всей строкой, а не отдельными столбцами. Разрешения таблиц могут это делать, но только на основе роли postgres, а не динамически зависящей от данных - так что это будет работать только в том случае, если у вас есть две непересекающиеся пользовательские группы авторов и редакторов.   -  person Bergi    schedule 14.02.2021
comment
Спасибо! Я добавил ответ с чем-то, что, надеюсь, будет полезно для следующего человека   -  person Cameron    schedule 16.02.2021


Ответы (1)


Основываясь на расследовании и методах проб и ошибок, похоже, что это лучше всего решить с помощью специальной функции обновления сообщений.

Владелец может использовать эту функцию через GraphQL / Postgraphile:

create function updatePost(
  headline text,
  body text,
  summary text
) returns post as $$
-- implement this function to check that the user found via 
-- app_hidden.current_user_id() exists in join table
-- with an `owner` permission
 -- then modify post
$$ language plpgsql strict security definer;

Редактор может использовать эту функцию через GraphQL / Postgraphile:

create function updatePostMeta(
  summary text
) returns post as $$
-- implement this function to check that the user found via 
-- app_hidden.current_user_id() exists in join table 
-- with an `editor` or `owner` permission
-- then modify post
$$ language plpgsql strict security definer;

Кроме того, используя RLS, можно было бы запретить кому-либо изменять post напрямую через GraphQL / Postgraphile, поэтому мы разрешили бы пользователям SELECT только из post

person Cameron    schedule 16.02.2021