#postgresql #postgraphile
Вопрос:
У меня есть нарушение политики RLS в функции Postgres. Я считаю, что это связано с тем, что политика основывается на строках, созданных в функции. В 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
. Я запускаю постграф, так что две мутации. У меня есть внешние ключевые отношения между ними. Я не знаю, будет ли 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
последним вставленным идентификатором. Мне нужна политика, чтобы пользователи из этого отношения присоединения видели только строки своей организации 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()));
Комментарии:
1. Ваша функция
RETURNS setof public.message
. Какой вообще смысл присоединяться к результату противmoved_tags
? Это только приведет к дубликатам. Вместо этого верните вставленное сообщение (которое, вероятно, должно быть единственным), а затем выберите теги этого, используя graphql. Это гарантируетmessage_tag
, что запрос к таблице будет отправлен только после вставки всех строк.2. «У меня есть нарушение политики RLS в функции Postgres. «- в чем именно заключается ошибка? Какие результаты вы получаете, когда вызываете функцию? Каков ожидаемый результат?
3. @Bergi Спасибо. В этом есть смысл. В графическом файле есть поле запроса в полезной нагрузке мутации.
4. Я удалил возвращающую инструкцию SELECT, но по-прежнему получаю ошибку. Похоже, это ВСТАВКА. Я обновил вопрос, добавив, пожалуйста, дополнительную информацию.
5. Что делать, если я создам новую политику на основе значения конфигурации, заданного в функции? Перед вставкой установите значение конфигурации в значение true. После этого установите для него значение false.
Ответ №1:
Согласно сообщению об ошибке, эта часть вашей инструкции 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
пунктом.
Комментарии:
1. Я никогда раньше не видел ан И в А. Когда я попытался это сделать, я получил синтаксическую ошибку, указывающую прямо на «И». Я скопировал свою политику и добавил ее для ВСТАВКИ, но с той же ошибкой. У меня также есть другая политика, которая просто проверяет наличие сеанса пользователя при ВСТАВКЕ. Я думаю, что это связано с несуществующей строкой, потому что она находится в середине функции. Я запускаю команды отдельно в CLI, и это работает.
2. Я забыл, что полис может быть только один
FOR
. Вам придется добавить вторую политику. Сообщение об ошибке однозначное, оно жалуется на незаконноеINSERT
. Вы не показали ту другую политику, поэтому я не могу сказать, что именно не так.3. Я обновил вопрос с помощью другой политики. Один из моих успехов заключается в запуске функции SELECT set_config(‘политика. allow_message_tag’, ‘t’, true). Затем, имея политику, которая позволяет вставлять, если задана эта конфигурация. В конце функции я вернул эту конфигурацию на «f». Похоже, он работает в командной строке, но не с конечной точки графического файла, над которой я работаю.
4. Тогда именно эта политика терпит неудачу.
current_user_id()
должна быть определяемая пользователем функция. По крайней мере, вы знаете, в каком направлении отлаживать.
Ответ №2:
Я закончил тем, что добавил поле в присоединяемую таблицу и с его помощью создал политику. Таким образом, для проверки RLS не требуется строка, которая была бы создана в середине функции.