JavaRush /Курсы /SQL SELF /Контроль доступа на уровне строк: Row-Level Security (RLS...

Контроль доступа на уровне строк: Row-Level Security (RLS)

SQL SELF
47 уровень , 3 лекция
Открыта

Если права на уровне ролей и таблиц — это "охранник у входной двери", то Row-Level Security — это индивидуальный охранник, который проверяет, можно ли тому или иному пользователю заходить в каждую отдельную комнату в здании.

RLS помогает сделать так, чтобы пользователь мог работать только с теми строками в таблице, которые ему разрешены. Например:

  • В интернет-магазине менеджер должен видеть только свои заказы.
  • В CRM-платформе сотрудник видит только клиентов своей команды.
  • В банковской системе клиент должен иметь доступ только к своим счетам.

Как работает RLS

В основе работы RLS лежит концепция политик доступа. Политики определяют, какие строки таблицы видимы для роли или пользователя и какие доступны для изменений (INSERT, UPDATE, DELETE).

По умолчанию RLS отключён для всех таблиц, и включить его можно вручную.

Включение RLS для таблицы

Давайте создадим таблицу orders, где хранятся заказы интернет-магазина:

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    user_id INT NOT NULL,
    product_name TEXT NOT NULL,
    price NUMERIC NOT NULL
);

Добавим несколько тестовых данных:

INSERT INTO orders (user_id, product_name, price)
VALUES
    (1, 'Смартфон', 500),
    (2, 'Ноутбук', 1000),
    (1, 'Наушники', 100),
    (3, 'Клавиатура', 50);

Теперь включим RLS для этой таблицы:

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

Что мы сделали? Мы активировали механизм RLS, но сами политики ещё не установлены. Пока политики не созданы, RLS фактически не влияет на доступ к таблице.

Создание политики доступа

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

CREATE POLICY имя_политики
ON таблица
[FOR { SELECT | INSERT | UPDATE | DELETE }]
TO роль
USING (условие_доступа)
WITH CHECK (условие_проверки);
  • FOR: определяет, для каких операций применяется политика (SELECT, INSERT, UPDATE, DELETE). Если пропустить этот параметр, политика применяется ко всем операциям.
  • TO: указывает, для каких ролей политика активна. Если не указано, политика применяется к любой роли.
  • USING: задаёт условие, при выполнении которого строки будут видны пользователю.
  • WITH CHECK: определяет условие проверки для операций INSERT и UPDATE.

Пример: доступ только к своим заказам

Создадим политику, которая разрешает пользователям видеть только свои заказы. Пусть идентификатор текущего пользователя совпадает с user_id в таблице:

CREATE POLICY user_can_view_own_orders
ON orders
FOR SELECT
USING (user_id = current_user::INT);

Что здесь происходит?

  • Политика называется user_can_view_own_orders.
  • Она применяется к операции SELECT.
  • Только строки, где user_id совпадает с идентификатором текущего пользователя (current_user), видимы.

Итак, если вы вошли в систему как пользователь с user_id = 1, вы увидите только свои заказы.

Проверка работы RLS

Создадим двух пользователей: user1 и user2.

CREATE ROLE user1 LOGIN PASSWORD 'password1';
CREATE ROLE user2 LOGIN PASSWORD 'password2';

Назначим роли доступ к таблице:

GRANT SELECT ON orders TO user1, user2;

Теперь переключимся на пользователя user1 и попробуем выполнить запрос:

SELECT * FROM orders;

Результат: вы увидите только строки, где user_id = 1.

Политики для INSERT

Скажем, мы хотим разрешить пользователям добавлять только свои заказы (т.е. строка с user_id должна совпадать с идентификатором текущего пользователя).

Создадим политику на INSERT:

CREATE POLICY user_can_insert_own_orders
ON orders
FOR INSERT
WITH CHECK (user_id = current_user::INT);

Теперь, если пользователь user1 попытается добавить заказ, где user_id не равен 1, то запрос завершится с ошибкой.

Политики для UPDATE и DELETE

Подобным образом можно создавать политики для изменения и удаления данных. Например:

Для обновления своих данных:

CREATE POLICY user_can_update_own_orders
ON orders
FOR UPDATE
USING (user_id = current_user::INT)
WITH CHECK (user_id = current_user::INT);

Для удаления своих данных:

CREATE POLICY user_can_delete_own_orders
ON orders
FOR DELETE
USING (user_id = current_user::INT);

Применение нескольких политик

Вы можете создать несколько политик для одной таблицы. Все они будут применяться одновременно. Например, если для одной роли действует несколько правил, PostgreSQL проверит их все (логическое И).

Проверка и отладка RLS

Чтобы проверить, какие политики установлены для таблицы, используйте команду:

\di+ имя_таблицы

Если вы хотите временно отключить RLS (например, для администратора), выполните:

ALTER TABLE orders DISABLE ROW LEVEL SECURITY;

Администраторская роль SUPERUSER по умолчанию не ограничена RLS, поэтому может видеть все данные.

Типичные ошибки при настройке RLS

Ошибки могут возникнуть, если вы забудете:

  • Активировать RLS командой ALTER TABLE ... ENABLE ROW LEVEL SECURITY.
  • Установить соответствующие политики для всех операций (SELECT, INSERT, UPDATE, DELETE).
  • Корректно указать условие в USING и WITH CHECK. Например, не проверив user_id, можно случайно открыть доступ ко всем строкам.

Row-Level Security — это один из самых мощных инструментов безопасности в PostgreSQL. Он позволяет настроить доступ с точностью до строки и автоматизировать управление доступом, что особенно важно для сложных приложений с высокими требованиями к защите данных.

2
Задача
SQL SELF, 47 уровень, 3 лекция
Недоступна
Комплексные политики: доступ для чтения и редактирования
Комплексные политики: доступ для чтения и редактирования
Комментарии (9)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Anonymous #3449047 Уровень 61
16 ноября 2025
В валидаторе задачи какой-то глюк с name/username. В таблице employees нет поля username, есть nameб но валидатор требует username
Vlad Tagunkov Уровень 21
1 февраля 2026
глюк остался. пришлось в таблице все наймы менять на юзернеймы - тогда валидатор принял задачу.
Евгений Уровень 49 Expert
5 ноября 2025
\di+ возвращает индексы, для таблиц нужен \d+
Евгений Уровень 49 Expert
5 ноября 2025
Немного некорректно описаны USING и WITH CHECK. USING - это условие, проверяющее возможность прочитать строку. Оно используется не только для SELECT, но и для операций, которые сначала получают строку, чтобы с ней что-то сделать (DELETE, UPDATE). WITH CHECK - это условие, которое проверяет новую / изменённую строку (UPDATE, INSERT), т.е. оно будет применено после выполнения операции.
Евгений Уровень 49 Expert
5 ноября 2025
Логично, что для политик, связанных с UPDATE, надо использовать обе проверки. Но можно использовать только одну в случае с USING. Если мы используем только USING (user_name = current_user), то мы сможем изменять только "принадлежащую" нам строку, но мы, например, можем поменять значение user_name на чужое, тогда обновление выполнится, но в будущем мы обновлять данную строку не сможем. А вот WITH CHECK для операции UPDATE отдельно без USING использоваться не может, я проверил, либо я не смог найти такую сит. Также, UPDATE политика всегда требует наличия отдельной SELECT политики: ссылка, ссылка на документацию.
Ra Уровень 1 Student
15 августа 2025
current_user::INT это то ли не Постгрес, то ли галлюцинации. GRANT SELECT, UPDATE ON employees TO PUBLIC; SET ROLE alice; этого по моему не было в теории
Евгений Уровень 49 Expert
5 ноября 2025
current_user::INT - выдумка авторов
Ra Уровень 1 Student
15 августа 2025
Я прав или что-то тут не верно?

| Параметр   | Когда применяется       | Что проверяет                              | Цель                                                                 |
|------------|-------------------------|--------------------------------------------|----------------------------------------------------------------------|
| `USING`    | SELECT, DELETE          | Существующие строки (должны удовлетворять условию) | **Фильтрация видимости**: какие строки пользователь может видеть/удалять. |
| WITH CHECK | INSERT, UPDATE          | Новые или измененные строки (должны удовлетворять условию) | **Валидация изменений**: какие данные пользователь может добавить/изменить. |
Евгений Уровень 49 Expert
5 ноября 2025
Для UPDAE тоже нужен USING