Как настроить роли пользователей: администратор, менеджер, клиент – полное разграничение прав
Вы когда-нибудь давали менеджеру доступ к CRM, а он случайно удалил заказы другого менеджера? Или клиент увидел чужие заявки из-за ошибки в URL? Это называется «проблема разграничения прав доступа», и она может стоить вам клиентов, денег и нервов.
В Falcon Space разграничение прав строится на трёх уровнях: доступ к страницам (роли), доступ к данным (фильтрация в SQL-процедурах) и доступ к действиям (кнопки). Это гибкая система, которая позволяет настроить права так, что каждый пользователь будет видеть ровно то, что ему положено. Расскажу, как это работает на практике.
Три кита разграничения прав в Falcon Space
В платформе нет жёстких предопределённых ролей. Вы сами создаёте роли под свой бизнес: «Клиент», «Менеджер», «Директор», «Бухгалтер», «Супервайзер» — любые. Каждая роль — это просто имя и набор разрешений.
Разграничение строится так:
- Уровень страниц — кто может видеть страницу (например, страница «Управление пользователями» доступна только роли «Администратор»).
- Уровень данных — какие строки из таблицы видит пользователь (например, менеджер видит только свои заказы, директор — все).
- Уровень действий — какие кнопки и операции доступны (например, менеджер может редактировать заказ, клиент — только просматривать).
Рассмотрим каждый уровень подробно.
Уровень 1. Ограничение доступа к страницам
В Falcon Space каждая страница имеет поле «Роли». Вы указываете через запятую, какие роли могут видеть эту страницу. Например: Роли: Admin, Manager. Если пользователь не входит ни в одну из этих ролей, при попытке открыть страницу он получит ошибку 403 (доступ запрещён).
Это самый простой и эффективный способ скрыть от лишних глаз целые разделы. Например:
- Страница «Финансовые отчёты» — только для ролей «Директор», «Бухгалтер».
- Страница «Управление ролями» — только для «Администратор».
- Страница «Мои заказы» — для «Клиент», «Менеджер», «Директор» (но данные будут разные, см. уровень 2).
Настройка делается через административный интерфейс: выбираете страницу, редактируете поле «Роли», сохраняете. Всё, никакого кода.
Уровень 2. Ограничение доступа к данным (строчкам таблиц)
Это самый тонкий момент. У вас есть таблица заказов, и разные пользователи должны видеть разные заказы. Клиент — только свои. Менеджер — заказы своего отдела. Директор — все.
В Falcon Space это реализуется через передачу параметра @username в хранимые процедуры. Система автоматически подставляет имя текущего пользователя (логин) во все вызовы процедур. Внутри процедуры вы пишете условие, например:
CREATE PROCEDURE [app].[get_orders]
@username nvarchar(100)
AS
BEGIN
-- Для клиента: только его заказы
IF EXISTS (SELECT 1 FROM users WHERE username = @username AND role = 'Client')
SELECT * FROM orders WHERE client_username = @username;
-- Для менеджера: заказы его подразделения
ELSE IF EXISTS (SELECT 1 FROM users WHERE username = @username AND role = 'Manager')
SELECT o.* FROM orders o
JOIN departments d ON o.department_id = d.department_id
JOIN users u ON u.department_id = d.department_id
WHERE u.username = @username;
-- Для директора: все заказы
ELSE IF EXISTS (SELECT 1 FROM users WHERE username = @username AND role = 'Director')
SELECT * FROM orders;
ELSE
SELECT NULL WHERE 1=0; -- ничего не возвращаем
END
Важно: никогда не доверяйте параметрам, переданным с клиента. Например, не делайте так: WHERE order_id = @order_id_from_request без проверки, принадлежит ли этот заказ пользователю. Злоумышленник может подставить чужой order_id и получить чужие данные. Всегда используйте @username как идентификатор текущего пользователя.
Такой подход гарантирует, что даже если пользователь угадает URL или передаст чужой ID, он не увидит чужие данные — процедура сама отфильтрует.
Пример с иерархией: менеджер видит подчинённых
Часто нужно, чтобы начальник видел данные подчинённых. Добавляем в таблицу пользователей поле manager_id. В процедуре делаем рекурсию (через CTE) или просто выбираем всех, у кого менеджер = текущий пользователь.
WITH subordinates AS (
SELECT user_id FROM users WHERE manager_username = @username
UNION ALL
SELECT u.user_id FROM users u
JOIN subordinates s ON u.manager_username = (SELECT username FROM users WHERE user_id = s.user_id)
)
SELECT * FROM orders WHERE client_username IN (SELECT username FROM users WHERE user_id IN (SELECT user_id FROM subordinates));
Так можно строить сколь угодно глубокие иерархии.
Уровень 3. Ограничение доступа к действиям (кнопкам)
Даже если пользователь видит заказ, он не обязательно должен иметь возможность его редактировать или удалять. В Falcon Space каждая кнопка, ссылка, форма привязаны к определённой процедуре. Вы можете в процедуре сделать проверку роли и, если пользователь не имеет права, вернуть ошибку или просто не выполнять действие.
Пример: процедура удаления заказа должна быть доступна только менеджеру и директору, но не клиенту.
CREATE PROCEDURE [app].[delete_order]
@order_id int,
@username nvarchar(100)
AS
BEGIN
-- Проверяем роль
DECLARE @role nvarchar(50);
SELECT @role = role FROM users WHERE username = @username;
IF @role NOT IN ('Manager', 'Director')
BEGIN
SELECT 'error' AS result, 'У вас нет прав на удаление заказов' AS message;
RETURN;
END
-- Дополнительная проверка: может, заказ уже оплачен? Тогда удалять нельзя.
IF EXISTS (SELECT 1 FROM orders WHERE order_id = @order_id AND status = 'Paid')
BEGIN
SELECT 'error' AS result, 'Нельзя удалить оплаченный заказ' AS message;
RETURN;
END
DELETE FROM orders WHERE order_id = @order_id;
SELECT 'success' AS result;
END
На странице кнопка «Удалить» будет видна всем, но при нажатии вызовется процедура и отклонит запрос, если у пользователя нет прав. Альтернативно — можно скрыть кнопку по роли прямо в HTML, но проверка на сервере обязательна (на случай, если пользователь отправит запрос в обход интерфейса).
Расширенная настройка: столбцы таблицы в зависимости от роли
Иногда нужно, чтобы разные роли видели разные столбцы в одной таблице. Например, менеджер видит цену закупки, а клиент — нет. В процедуре можно динамически формировать SELECT:
IF @role = 'Manager'
SELECT order_id, client_name, total_sum, purchase_price, profit;
ELSE
SELECT order_id, client_name, total_sum;
Или возвращать одно и то же, но на фронтенде скрывать колонки через CSS (менее безопасно).
Реальный пример: CRM для автосервиса (6 ролей)
В кейсе с автосервисом (см. предыдущие статьи) мы использовали роли:
- Клиент — видит только свои заказы, не видит себестоимость, не может редактировать заказы.
- Мастер — видит заказы, назначенные на него, может менять статус, добавлять комментарии, не видит финансов.
- Менеджер — видит все заказы своего филиала, может назначать мастеров, менять статусы, просматривать себестоимость.
- Завскладом — видит только складские таблицы, не видит заказы клиентов.
- Бухгалтер — видит финансовые отчёты, зарплаты, но не может редактировать заказы.
- Директор — видит всё, может всё.
Для каждой роли мы создали отдельную процедуру вывода данных, либо общую с условиями. Это заняло несколько дней проектирования, но зато система работает без сбоев уже год, и ни один пользователь не смог увидеть чужие данные.
Из отзыва: «Гибкое разделение видимости данных в зависимости от должности сотрудника и его места работы. Множество аналитических отчётов. Фиксация действий: изменение полей, сохранение форм, посещение страниц».
Логирование действий: кто и что делал
Права доступа бесполезны, если вы не знаете, что происходит. Рекомендуем включить логирование всех критических действий: создание/изменение/удаление заказов, изменение цен, вход в систему, выгрузка отчётов. В Falcon Space это делается через триггеры в SQL или через вызов процедуры логирования из каждой бизнес-процедуры.
Пример триггера на таблицу заказов:
CREATE TRIGGER trg_orders_audit ON orders
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
INSERT INTO audit_log (table_name, action, username, changed_data, changed_at)
SELECT 'orders',
CASE WHEN EXISTS (SELECT 1 FROM inserted) AND EXISTS (SELECT 1 FROM deleted) THEN 'UPDATE'
WHEN EXISTS (SELECT 1 FROM inserted) THEN 'INSERT'
ELSE 'DELETE' END,
SYSTEM_USER,
(SELECT * FROM inserted FOR JSON PATH),
GETDATE();
END
Теперь при любом изменении заказа вы знаете, кто и когда это сделал. Это дисциплинирует сотрудников и помогает расследовать инциденты.
Как настроить роли в Falcon Space: пошаговая инструкция
- Создайте роли через административный интерфейс: раздел «Роли» → «Добавить». Укажите название роли (например, «Manager»).
- Назначьте роли пользователям — либо при регистрации (выбор из списка), либо через редактирование профиля администратором.
- На страницах укажите допустимые роли — откройте страницу, найдите поле «Роли», введите имена ролей через запятую.
- Модифицируйте хранимые процедуры, добавив в них проверку роли и фильтрацию по @username.
- Протестируйте, зайдя в систему под разными учётными записями.
Всё это можно сделать без программирования, кроме шага 4 (написание условий в SQL). Но SQL-условия — это база, которую может освоить даже не программист за пару дней.
Типичные ошибки при настройке прав
- Забыли про @username в процедуре — тогда все увидят все данные. Проверяйте каждую процедуру, которая возвращает данные.
- Слишком много ролей (например, 20). Усложняете поддержку. Оптимально 4-6 ролей, остальное — через флаги в таблицах.
- Не разграничили права на уровне страниц — пользователь может угадать URL и зайти в чужой раздел (но если процедуры фильтруют, опасности нет, но лучше скрыть).
- Дали менеджеру права на удаление без подтверждения — добавьте второй фактор или корзину с восстановлением.
Что делать, если у вас уже есть сайт без разграничения прав
Проведите аудит: какие страницы, какие процедуры. Начните с малого — добавьте проверку роли на странице «Мои заказы» для клиентов. Затем распространите на другие. Часто достаточно просто добавить условие WHERE client_username = @username в существующие процедуры, и проблема решена.
Мы можем помочь вам с аудитом и доработкой прав. Стоимость — от 20 до 100 тыс. руб в зависимости от объёма. Зато вы будете спать спокойно.
Итог: разграничение прав в Falcon Space — это комбинация ролей на страницах, фильтрации по @username в SQL-процедурах и проверки роли в действиях. При правильной настройке вы получите систему, где каждый пользователь видит только своё, а вы контролируете каждый шаг. Не пренебрегайте безопасностью.
- Шаг 1. Создать концепт проекта
- Шаг 2. Получить оценку бюджета (КП)
- Шаг 3. Заключить договор
- Шаг 4. Создать совместно техническое задание
- Шаг 5. Поэтапная реализация проекта