Как настроить гранулярный доступ к данным: чтобы менеджер видел только свои заказы, а директор – все
У вас CRM с менеджерами. Каждый менеджер работает со своими клиентами. Проблема: менеджеры не должны видеть чужие заказы, чтобы случайно их не испортить. А директор должен видеть все заказы. И ещё начальник отдела должен видеть заказы подчинённых, но не других отделов. Это называется гранулярный доступ на уровне строк (row-level security).
В Falcon Space такая настройка делается через передачу параметра @username в SQL-процедуры и условия WHERE. Расскажу, как это работает и как настроить у себя.
Почему простых ролей недостаточно
Роли (администратор, менеджер, клиент) ограничивают доступ к страницам. Например, страница «Список заказов» доступна и менеджеру, и директору. Но менеджер должен видеть только заказы, где он назначен ответственным, а директор — все. Это и есть гранулярный доступ на уровне строк.
В Falcon Space нет встроенного «магического» фильтра по строке, но есть стандартный механизм: каждая хранимая процедура, возвращающая данные, получает параметр @username (текущий пользователь). Вы внутри процедуры пишете условие WHERE, которое фильтрует записи в зависимости от роли и привязки к пользователю.
Базовая схема: фильтр по владельцу
Самый простой случай: заказы привязаны к менеджеру через поле manager_id. Процедура:
CREATE PROCEDURE [app].[get_orders]
@username nvarchar(100)
AS
BEGIN
DECLARE @role nvarchar(50), @user_id int;
SELECT @role = role, @user_id = user_id FROM users WHERE username = @username;
IF @role = 'Director'
SELECT * FROM orders;
ELSE IF @role = 'Manager'
SELECT o.* FROM orders o
WHERE o.manager_id = @user_id;
ELSE
SELECT * FROM orders WHERE customer_username = @username;
END
Директор видит всё, менеджер — только свои заказы, клиент — только свои.
Реальный кейс: сеть автосервисов с филиалами
В проекте для сети СТО требовалось, чтобы менеджер филиала видел заказы только своего филиала, директор сети — все филиалы, а мастер — только назначенные ему заказы.
Мы добавили таблицу users с полями branch_id, role. Заказы имеют branch_id (филиал) и master_id.
Процедура для мастера:
IF @role = 'Master'
SELECT * FROM orders
WHERE master_id = @user_id AND branch_id = (SELECT branch_id FROM users WHERE user_id = @user_id);
Для менеджера филиала:
ELSE IF @role = 'BranchManager'
SELECT * FROM orders WHERE branch_id = (SELECT branch_id FROM users WHERE user_id = @user_id);
Директор сети не имеет branch_id или имеет NULL — для него условие без фильтра.
Это позволило каждому сотруднику работать только со своими данными. Ошибок доступа не было ни разу за год.
Иерархия: начальник видит подчинённых
Для иерархии добавляем поле manager_id в таблицу users. Процедура рекурсивно находит подчинённых:
WITH subordinates AS (
SELECT user_id FROM users WHERE manager_id = @user_id
UNION ALL
SELECT u.user_id FROM users u
INNER JOIN subordinates s ON u.manager_id = s.user_id
)
SELECT o.* FROM orders o
WHERE o.manager_id IN (SELECT user_id FROM subordinates)
OR o.manager_id = @user_id;
Так можно строить сколь угодно глубокие иерархии.
Защита от подмены ID в URL
Даже если список заказов отфильтрован, пользователь может перейти по URL /order/123 (где 123 — чужой заказ). Чтобы это предотвратить, в процедуре получения одного заказа также проверяем права:
CREATE PROCEDURE [app].[get_order_details]
@order_id int,
@username nvarchar(100)
AS
BEGIN
DECLARE @user_id int, @role nvarchar(50);
SELECT @user_id = user_id, @role = role FROM users WHERE username = @username;
SELECT o.* FROM orders o
WHERE o.order_id = @order_id
AND (
@role = 'Director'
OR (@role = 'Manager' AND o.manager_id = @user_id)
OR (@role = 'Client' AND o.client_username = @username)
);
END
Если ничего не вернулось — доступ запрещён.
Как настроить это в Falcon Space
- В таблице, которую нужно фильтровать, добавьте поле, связывающее запись с пользователем (например, responsible_user_id).
- Во всех хранимых процедурах, которые возвращают данные из этой таблицы, добавьте параметр @username (если его нет — добавьте).
- Внутри процедуры получите role и user_id текущего пользователя.
- Добавьте условный WHERE с фильтром по роли.
- Проверьте, что процедуры редактирования/удаления также содержат проверку прав.
Всё делается на чистом SQL. Мы помогаем с настройкой за 1-2 дня (20-50 тыс. руб).
Гранулярный доступ — это не роскошь, а требование безопасности и удобства. Настройте его один раз, и ваши сотрудники будут видеть только то, что им положено.
- Шаг 1. Создать концепт проекта
- Шаг 2. Получить оценку бюджета (КП)
- Шаг 3. Заключить договор
- Шаг 4. Создать совместно техническое задание
- Шаг 5. Поэтапная реализация проекта