В этой главе подробно рассматривается устройство подсистемы пользователей, архитектура разграничения прав доступа (ACL) и механизмы безопасности в Seditio CMS. Вы узнаете, как распределяются роли пользователей, как устроена битовая маска прав доступа, как кэшируются права в базе данных, а также принципы авторизации и шифрования.
4.1. Группы пользователей и системные роли
Система управления доступом в Seditio построена на ролевой модели. Все зарегистрированные пользователи обязательно состоят в группах.
4.1.1. Системные (зарезервированные) группы пользователей
В Seditio по умолчанию присутствуют предопределенные группы с зарезервированными идентификаторами (ID), которые жестко завязаны на внутреннюю логику ядра:
- Guests (Гости / ID = 1): Неавторизованные посетители сайта. Группа определяет, к какому контенту и функционалу сайта есть публичный доступ.
- Inactive (Неактивные / ID = 2): Пользователи, прошедшие регистрацию, но ожидающие активации аккаунта (например, по ссылке из e-mail или после проверки администратором).
- Banned (Заблокированные / ID = 3): Пользователи, аккаунты которых временно или навсегда заблокированы.
- Members (Участники / ID = 4): Стандартная группа для всех успешно зарегистрированных и активированных пользователей сайта.
- Administrators (Администраторы / ID = 5): Члены команды с полными административными правами. Пользователи этой группы имеют доступ в панель управления (по адресу
/adminилиindex.php?module=adminбез ЧПУ) по умолчанию. - Moderators (Модераторы / ID = 6): Группа пользователей с модераторскими привилегиями на форумах и в категориях страниц.
4.1.2. Концепция основной группы и дополнительных групп
У каждого пользователя в Seditio есть две плоскости принадлежности к группам:
- Основная группа (
user_maingrp): Хранится в таблице пользователейsed_users. Она определяет базовую роль пользователя на сайте, его скин по умолчанию, язык интерфейса и уровень доступа. - Дополнительные группы (Таблица
sed_groups_users): Пользователь может состоять в неограниченном числе дополнительных групп. Принадлежность связывается через таблицу отношенийsed_groups_users(колонкиgru_useridиgru_groupid).
При проверке прав доступа ядро Seditio объединяет привилегии основной группы пользователя и всех дополнительных групп, в которых он состоит.
4.2. Архитектура и битовая маска ACL (Access Control List)
Вся матрица прав доступа в Seditio CMS хранится в таблице sed_auth. Запись о правах привязывается к группе пользователей (auth_groupid), области системы (auth_code — например, page, forums, admin) и конкретной опции внутри этой области (auth_option — например, категория страниц или раздел форума).
4.2.1. Байт как битовая маска прав доступа
Для минимизации размера базы данных и максимальной производительности права на конкретное действие хранятся в виде 8-битного целого числа (один байт от 0 до 255), где каждый бит отвечает за определенное разрешение:
- Бит 0 (вес 1):
Read(Чтение /R). Разрешает просмотр контента. - Бит 1 (вес 2):
Write(Запись /W). Разрешает добавление и редактирование собственного контента. - Бит 2 (вес 4): Пользовательское разрешение 1 (
1). - Бит 3 (вес 8): Пользовательское разрешение 2 (
2). - Бит 4 (вес 16): Пользовательское разрешение 3 (
3). - Бит 5 (вес 32): Пользовательское разрешение 4 (
4). - Бит 6 (вес 64): Пользовательское разрешение 5 (
5). - Бит 7 (вес 128):
Admin(Администрирование /A). Разрешает модерирование, удаление чужого контента и управление настройками раздела.
Таким образом, если группа имеет полные права на раздел (Чтение + Запись + Администрирование), значение её прав в БД будет равно 1 + 2 + 128 = 131.
4.2.2. Наследование и кумулятивное сложение прав
Если пользователь состоит в нескольких группах одновременно, система не перезаписывает права одной группы правами другой, а применяет принцип кумулятивного сложения (побитового ИЛИ).
При авторизации пользователя функция sed_auth_build() запрашивает права для всех групп, в которых состоит пользователь, и собирает их в единую сетку прав с использованием побитового оператора ИЛИ (|=):
// Cumulative bitwise OR merging of user rights from multiple groups @$authgrid[$row['auth_code']][$row['auth_option']] |= $row['auth_rights'];
Пример:
- Пользователь состоит в группе Members, у которой права на чтение форума равны
1(только Чтение). - Этот же пользователь состоит в дополнительной группе Moderators, у которой права на этот же форум равны
128(Администрирование). - Итоговые права пользователя составят
1 | 128 = 129(Чтение + Администрирование).
4.3. Процесс проверки авторизации в коде (sed_auth)
Ядро системы использует встроенные функции для построения и проверки сетки прав.
4.3.1. Сборка сетки прав при входе пользователя
При успешной авторизации или при первом обращении к странице вызывается функция sed_auth_build(), расположенная в файле system/functions.php. Она сканирует все группы пользователя, в которых он состоит (основную и дополнительные), выполняет SQL-запрос к таблице sed_auth и строит двумерный ассоциативный массив с правами:
$usr['auth'][$area][$option] = $bitwise_rights;
Сигнатура функции:
function sed_auth_build($userid, $maingrp = 0)
- Логика гостей: Если
$useridравен0или$maingrpравен0, функция автоматически считает пользователя гостем и присваивает ему ID группы Guests (ID = 1). - Сбор всех групп: Для авторизованных пользователей в список групп добавляется
$maingrp, а также все ID групп из таблицы отношенийsed_groups_usersпо запросу к БД. - Групповое объединение: Выполняется единый SQL-запрос выборки прав для всех найденных групп:
SELECT auth_code, auth_option, auth_rights FROM sed_auth WHERE auth_groupid IN (...) ORDER BY auth_code ASC, auth_option ASC
В цикле права объединяются с помощью побитового ИЛИ (|=) в единый двумерный массив $authgrid:
@$authgrid[$row['auth_code']][$row['auth_option']] |= $row['auth_rights'];
Метод возвращает полученный массив $authgrid.
4.3.2. Проверка доступа в коде
Для проверки наличия прав в PHP-скриптах используется ключевая функция sed_auth() (файл system/functions.php). Она сопоставляет битовую маску запрашиваемых прав с правами текущего пользователя и возвращает булево значение (TRUE или FALSE) либо массив результатов (если запрашивается проверка нескольких масок одновременно).
Сигнатура функции:
function sed_auth($area, $option, $mask = 'RWA')
Параметры:
$area(string) — защищаемая область системы (например,'page','forums','admin').$option(string) — конкретный подраздел или категория (например,'news'для категории страниц).$mask(string) — строка проверяемых прав (по умолчанию'RWA').
Внутренняя логика проверки:
- Функция разбивает строку маски
$maskна отдельные символы-биты (черезstr_split()) и сопоставляет их с числовыми весами:R = 1,W = 2,1 = 4,2 = 8,3 = 16,4 = 32,5 = 64,A = 128. - Опция any: Если параметр
$optionпередан как'any'(проверка наличия права на что угодно в рамках области), функция проверяет всю ветку$usr['auth'][$area]на присутствие хотя бы одной записи с этим битом. Дополнительно, если запрашивается право администратора (A) и у текущего пользователя есть права суперадминистратора (admin/a), функция автоматически вернетTRUE. - Обычная проверка: В остальных случаях проверяется точное пересечение побитового ИЛИ:
($usr['auth'][$area][$option] & $weight) == $weight. - Возвращаемое значение: Если передана строка маски из одной буквы (например,
'R'), функция возвращает одно булево значение (TRUEилиFALSE). Если передана маска из нескольких букв (например,'RWA'), возвращается массив булевых результатов (например,[TRUE, FALSE, FALSE]), что позволяет использовать конструкциюlist():
list($usr['auth_read'], $usr['auth_write'], $usr['isadmin']) = sed_auth('page', 'news', 'RWA');
4.3.3. Оптимизация производительности: кэширование прав
Для того чтобы избежать выполнения ресурсоемких SQL-запросов и побитового объединения массивов прав при каждом клике пользователя, Seditio CMS кэширует готовую сетку прав авторизованного пользователя:
- В таблице
sed_usersпредусмотрено полеuser_authтипаTEXT. - При первой сборке прав результат работы
sed_auth_build()сериализуется черезserialize()и сохраняется в это поле. - При каждом последующем обращении к страницам права пользователя мгновенно загружаются из базы данных одной строкой и десериализуются:
$usr['auth'] = unserialize($row['user_auth']);. - Сброс кэша (функция
sed_auth_clear): При изменении прав групп в админке, редактировании структуры категорий или добавлении пользователей в новые группы система вызывает функциюsed_auth_clear($id)(файлsystem/functions.php). Если параметр$idравен'all', кэш сбрасывается для всех пользователей системы (UPDATE sed_users SET user_auth=''), если передан числовой ID — кэш прав сбрасывается точечно только для этого пользователя.
4.4. Профиль пользователя и механизм его расширения
Каждый пользователь имеет индивидуальную карточку профиля, данные которой хранятся в таблице sed_users.
[!NOTE]
Логика вывода форм регистрации, авторизации, изменения настроек в кабинете и публичной информации о пользователях на сайте обрабатывается встроенным модулем
users(подробное описание его структуры, контроллеров и TPL-шаблонов приведено в Главе 5. Встроенные модули).
4.4.1. Системная структура профиля
В состав профиля по умолчанию входят следующие ключевые поля:
user_id— уникальный идентификатор пользователя.user_name— логин (уникальное имя для авторизации).user_passwordиuser_salt— хэш пароля и соль.user_maingrp— основная группа пользователя.user_email— адрес электронной почты.user_avatarиuser_photo— аватар и фотография.user_timezone,user_lang,user_skin— региональные настройки (часовой пояс, язык, тема оформления).user_regdate,user_lastlog,user_lastip— статистика активности.
4.4.2. Расширение профиля с помощью словарей
Если стандартных полей профиля недостаточно (например, требуется добавить поля «Номер телефона», «Адрес доставки» или «Telegram ID»), администратор может расширить профиль без изменения исходного PHP-кода:
- В разделе «Словари» по адресу
/admin/dic(илиindex.php?module=admin&m=dicбез ЧПУ) создается новый словарь. - Целевой таблицей выбирается таблица пользователей
users. - Создаются элементы словаря (
sed_dic/sed_dic_items). - Система выполняет SQL-запрос
ALTER TABLE sed_users ADD user_field_name ..., физически расширяя структуру базы данных. - Новое поле автоматически интегрируется в форму редактирования профиля в кабинете пользователя, в панель администрирования и становится доступно в TPL-шаблонах через теги вида
{USER_FIELD_NAME}.
4.5. Механизм сессий, авторизации и безопасности
Безопасность авторизации пользователей обеспечивается комплексом мер на уровне сессий, кук и криптографического хэширования.
4.5.1. Схема авторизации и Persistent Login
В Seditio поддерживается три режима авторизации (задаются через конфигурацию $cfg['authmode'] в datas/config.php):
- Только куки (режим 1): Авторизация привязана исключительно к cookie-файлам клиента.
- Только сессии (режим 2): Авторизация привязана к PHP-сессиям пользователя.
- Смешанный режим (режим 3): Используются и куки, и сессии (режим по умолчанию).
При авторизации через куки (режимы 1 и 3) Persistent Login базируется на специальной куке автологина с именем $sys['site_id']:
- Данные в куке хранятся в формате
base64и имеют структуру:user_id:_:user_secret:_:user_skin. - Обратите внимание: в куке хранится не пароль пользователя, а специальный секретный токен сеанса
user_secret(MD5-хэш), генерируемый и сохраняемый в базе данных при успешном входе. - При каждом запросе ядро считывает куку, декодирует её и сопоставляет поля с базой данных:
// Decoding persistent login cookie value
$u = base64_decode($_COOKIE[$sys['site_id']]);
$u = explode(':_:', $u);
$rsedition = sed_import($u[0], 'D', 'INT'); // User ID
$rseditiop = sed_import($u[1], 'D', 'H32'); // User Secret hash
$rseditios = sed_import($u[2], 'D', 'ALP'); // User Skin
- Если включена проверка по IP (
$cfg['ipcheck']), ядро дополнительно сверяет текущий IP-адрес запроса посетителя ($usr['ip']) со значением IP-адреса его последнего успешного входа (user_lastip), сохраненным в таблицеsed_users. В случае несовпадения (например, при смене сети пользователем) авторизация по куке сбрасывается.
4.5.2. Хэширование паролей и использование Site Secret
Для защиты паролей от компрометации в Seditio используется двухфакторное хэширование с солью с помощью функции sed_hash($data, $type, $salt) (файл system/functions.php):
- При регистрации для пользователя генерируется уникальная случайная соль (
user_salt). - Хэш пароля генерируется функцией
sed_hash()с параметром$type = 1. При этом глобальный секретный ключ сайта$cfg['site_secret']не используется:
// Hashing password with user salt (type = 1) $res = hash($algorithm, hash($algorithm, $password) . $salt);
- Глобальный уникальный ключ сайта
$cfg['site_secret'](задаваемый вdatas/config.phpпри установке) используется функциейsed_hash()с параметром$type = 2только для генерации уникального идентификатора сессии/токена сеанса (sessionid/user_secret):
// Hashing dynamic session identifier (type = 2) $res = hash($algorithm, hash($algorithm, $data) . $cfg['site_secret'] . $salt);
- Двойное хэширование (
md5по умолчанию) и индивидуальная соль защищают пароли от взлома по радужным таблицам (Rainbow Tables).
4.5.3. Защита от брутфорса и Бан-лист
- Аудит неудачных попыток входа: В системе ведется журнал логирования. Все неудачные попытки авторизации под любым именем записываются в лог безопасности (
sec), включая IP-адрес нападающего. - Блокировки по IP и e-mail (Бан-лист): В панели управления по адресу
/admin/banlist(илиindex.php?module=admin&m=banlistбез ЧПУ) администратор может блокировать доступ к сайту по конкретному IP-адресу, e-mail маске (например,*@spamdomain.com) или маске подсети. Система полностью поддерживает как IPv4, так и IPv6-адреса (полеbanlist_ipимеет типVARCHAR(45)). Проверка осуществляется функциейsed_check_banlist($userip)(файлsystem/functions.php), которая при обращении к любой странице сверяет IP посетителя с базой, автоматически строя маски для сравнения подсетей (например,192.168.1.*для IPv4 или2001:db8:85a3:0:*:*:*:*для IPv6). При обнаружении совпадения выполнение скрипта немедленно прерывается.
Comments: (0)