Модули
Политики доступа
Версия: 1.0
Дата: 2025-11-19
Статус: Реализован
Общее описание
Текущая реализация
Права доступа
Описание полей
UI/UX
Бизнес-логика
Выявленные проблемы
Рекомендации
Модуль "Политики доступа" — это центральный модуль системы авторизации . Он определяет:
Какие действия (политики) существуют в системе
Права по умолчанию для каждой группы пользователей
Индивидуальные права для конкретных пользователей
Это фундаментальный модуль, от которого зависят ВСЕ остальные модули системы!
Модуль Связь Использование Все модули check_access()Проверка прав на действия Группы пользователей group_policiesПрава по умолчанию для группы Администраторы user_policiesИндивидуальные права Менеджеры user_policiesИндивидуальные права (копируются из групповых) Производство user_policiesИндивидуальные права Дилеры group_policiesТолько групповые права!
Метрика Значение Всего политик 57 Групповых политик 124 Пользовательских политик 924
Категория Количество Администраторы 6 Дилеры (Компании) 9 Дилеры (Менеджеры) 10 Заказы 7 Календарь 1 Категории 4 Менеджеры 6 Новости 4 Склады 6 Товары 4
┌─────────────────────────────────────────────────────────────────────────────┐
│ СИСТЕМА АВТОРИЗАЦИИ (RBAC) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ policies │ │ groups │ │
│ │ (57 политик) │ │ (4 группы) │ │
│ │ │ │ │ │
│ │ key │ │ 1: Админ │ │
│ │ name │ │ 2: Дилер │ │
│ │ category │ │ 3: Менеджер │ │
│ │ description │ │ 4: Производство │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ └──────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────┐ │
│ │ group_policies │ ← Права по умолчанию │
│ │ (124 записи) │ │
│ │ │ │
│ │ group_id + policy_id + value│ │
│ └─────────────┬───────────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │Дилеры │ │Менедж.│ │Админы │ │
│ │(gr=2) │ │(gr=3) │ │(gr=1) │ │
│ └───┬───┘ └───┬───┘ └───┬───┘ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌─────────────────────────────┐ │
│ │ │ user_policies │ ← Индивидуальные права │
│ │ │ (924 записи) │ │
│ │ │ │ │
│ │ │ user_id + policy_id + value │ │
│ │ └─────────────────────────────┘ │
│ │ │
│ └──────► Права из group_policies НАПРЯМУЮ │
│ (без индивидуальных прав!) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Поле Тип Описание idbigint PK keystring Уникальный ключ политики namestring Название для отображения categorystring Категория (для группировки) descriptionstring Описание
Поле Тип Описание idbigint PK group_idFK Группа пользователей policy_idFK Политика valueboolean Включена/выключена
Поле Тип Описание idbigint PK user_idFK Пользователь policy_idFK Политика valueboolean Включена/выключена
app/
├── Http/Controllers/
│ └── PolicyController.php
├── Livewire/
│ ├── Policies/
│ │ └── Listing.php — Главная таблица политик
│ ├── Admins/Policies.php — Политики администратора
│ ├── Managers/Policies.php — Политики менеджера
│ └── Productions/Policies.php — Политики производства
└── Models/
├── Policy.php — Справочник политик
├── GroupPolicy.php — Групповые права
└── UserPolicy.php — Индивидуальные права
database/migrations/
├── 2024_03_06_194611_create_policies_table.php
├── 2024_03_06_194633_create_group_policies_table.php
└── 2024_03_06_194902_create_user_policies_table.php
// PolicyController.php — ТОЛЬКО АДМИНИСТРАТОРЫ
public function index ( Request $request)
{
$user = $request -> user ();
if ( ! $user or $user -> group_id != 1 ) // Жёсткая проверка
abort ( 403 );
return view ( 'templates.policies.table' );
}
Роль Просмотр Редактирование Администратор ✅ ✅ Менеджер ❌ ❌ Производство ❌ ❌ Дилер ❌ ❌
Колонка Описание Особенности keyКлюч политики Поиск nameНазвание Поиск categoryКатегория Поиск, фильтр, группировка descriptionОписание Поиск admin.valueПраво для Admin Toggle manager.valueПраво для Менеджер Toggle dealer.valueПраво для Dealer Toggle production.valueПраво для Production Toggle
┌─────────────────────────────────────────────────────────────────────────────┐
│ Политики доступа │
├─────────────────────────────────────────────────────────────────────────────┤
│ [Поиск...] [Фильтр 0] │
├─────────────────────────────────────────────────────────────────────────────┤
│ Права по умолчанию │
│ Key │ Название │ Admin │ Менедж │ Dealer │ │
├─────────────────────┴───────────────────────────┴───────┴────────┴────────┴─┤
│ Категория: Администраторы [▼] │
├─────────────────────────────────────────────────────────────────────────────┤
│ admin_can_view │ Может просматривать... │ ● │ ○ │ ○ │ ○ │
│ admin_can_auth │ Может авторизовыват... │ ● │ ○ │ ○ │ ○ │
│ admin_can_add │ Может добавлять... │ ● │ ○ │ ○ │ ○ │
│ admin_can_delete │ Может удалять... │ ● │ ○ │ ○ │ ○ │
│ admin_can_edit │ Может редактировать... │ ● │ ○ │ ○ │ ○ │
│ admin_can_edit_pol..│ Может редактировать п... │ ● │ ○ │ ○ │ ○ │
├─────────────────────────────────────────────────────────────────────────────┤
│ Категория: Дилеры (Компании) [▼] │
├─────────────────────────────────────────────────────────────────────────────┤
│ company_can_view │ Может видеть все ком... │ ○ │ ● │ ○ │ ○ │
│ ... │
└─────────────────────────────────────────────────────────────────────────────┘
Особенности:
✅ Группировка по категориям (collapsible)
✅ Inline Toggle для редактирования прав
✅ Фильтр по категории
✅ Поиск по всем полям
✅ 4 колонки с правами по группам
// User.php — ГЛАВНЫЙ МЕТОД ПРОВЕРКИ ПРАВ
public function check_access ($policy_key)
{
// 1. Суперадмин имеет все права
if ( $this -> superadmin == true ) {
return true ;
}
// 2. Поиск политики по ключу
$policy = Policy :: where ( 'key' , $policy_key) -> first ();
if ( ! $policy) {
return false ;
}
// 3. ВАЖНО! Для дилеров — ГРУППОВЫЕ права
if ( $this -> group_id == 2 ) {
$out = GroupPolicy :: where ( 'group_id' , 2 )
-> where ( 'policy_id' , $policy -> id)
-> first ();
} else {
// 4. Для остальных — ИНДИВИДУАЛЬНЫЕ права
$out = $this -> user_policies ()
-> where ( 'policy_id' , $policy -> id)
-> first ();
}
// 5. Возвращаем значение
if ($out) {
return ( bool ) $out -> value;
} else {
return false ;
}
}
┌─────────────────────────────────────────────────────────────────────────────┐
│ АЛГОРИТМ check_access() │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ check_access('admin_can_view') │
│ │ │
│ ▼ │
│ ┌───────────────────┐ │
│ │ superadmin == true │ ──YES──► return TRUE │
│ └─────────┬─────────┘ │
│ │ NO │
│ ▼ │
│ ┌───────────────────┐ │
│ │ Policy exists? │ ──NO──► return FALSE │
│ └─────────┬─────────┘ │
│ │ YES │
│ ▼ │
│ ┌───────────────────┐ │
│ │ group_id == 2? │ ──YES──► GroupPolicy::where('group_id', 2) │
│ │ (Дилер) │ │
│ └─────────┬─────────┘ │
│ │ NO │
│ ▼ │
│ user_policies()->where('policy_id', $policy->id) │
│ │ │
│ ▼ │
│ return (bool) $out->value │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
При создании менеджера (group_id = 3) групповые политики копируются в индивидуальные:
// User.php — boot()
static:: created ( function ( User $user) : void {
if (( int ) $user -> group_id === 3 ) {
$user -> seedManagerPoliciesFromGroupDefaults ();
}
});
// Метод копирования
public function seedManagerPoliciesFromGroupDefaults () : void
{
$groupPolicies = GroupPolicy :: query () -> where ( 'group_id' , 3 ) -> get ();
foreach ($groupPolicies as $gp) {
UserPolicy :: firstOrCreate (
[ 'user_id' => $this -> id, 'policy_id' => $gp -> policy_id],
[ 'value' => $gp -> value]
);
}
}
При открытии карточки редактирования пользователя создаются записи UserPolicy:
// Admins/Edit.php, Managers/Edit.php, Productions/Edit.php
public function mount ($id) : void
{
// ...
$policies = Policy :: all ();
foreach ($policies as $policy) {
UserPolicy :: firstOrCreate (
[ 'user_id' => $this -> record -> id, 'policy_id' => $policy -> id],
[ 'value' => false ]
);
}
}
Группа Источник прав Особенности Admin (1) user_policiesИндивидуальные права Дилер (2) group_policiesТОЛЬКО групповые! Нет индивидуальных Менеджер (3) user_policiesКопируются из групповых при создании Производство (4) user_policiesИндивидуальные права
Ключ Описание admin_can_viewМожет просматривать администраторов admin_can_authМожет авторизовываться в администраторов admin_can_addМожет добавлять администраторов admin_can_deleteМожет удалять администраторов admin_can_editМожет редактировать администраторов admin_can_edit_policyМожет редактировать права администраторов
Ключ Описание company_can_viewМожет видеть все компании company_manager_can_viewМожет видеть свои компании company_can_addМожет добавлять компании company_can_editМожет редактировать компании company_manager_can_editМожет редактировать свои компании company_can_deleteМожет удалять компании ... ...
Ключ Описание order_can_viewМожет смотреть заказы order_manager_can_viewМожет смотреть свои заказы order_can_editМожет редактировать заказы order_manager_can_editМожет редактировать свои заказы order_can_addМожет добавлять заказы order_can_deleteМожет удалять заказы order_can_delete_itemМожет удалять позиции заказа
# Проблема Файл Влияние — Критических проблем не обнаружено — —
# Проблема Описание Решение 1 Listing рендерит livewire.news.listing Неправильный view Заменить на livewire.base.listing 2 Дилеры без индивидуальных прав Нельзя дать индивидуальные права дилеру Добавить поддержку user_policies для дилеров 3 Жёсткая проверка group_id в контроллере Нет политики доступа к модулю Использовать check_access('policy_can_view')
# Проблема Описание 4 Нет CRUD для политик Нельзя создать/редактировать/удалить политику через UI 5 Нет аудита изменений Не логируется кто и когда менял права 6 Нет экспорта Нельзя выгрузить матрицу прав
// Policies/Listing.php:98 — было:
return view ( 'livewire.news.listing' );
// Стало:
return view ( 'livewire.base.listing' );
// User.php — check_access()
// Было:
if ( $this -> group_id == 2 ) {
$out = GroupPolicy :: where ( 'group_id' , 2 ) -> where ( 'policy_id' , $policy -> id) -> first ();
}
// Стало:
if ( $this -> group_id == 2 ) {
// Сначала проверяем индивидуальные права
$out = $this -> user_policies () -> where ( 'policy_id' , $policy -> id) -> first ();
// Если нет — берём групповые
if ( ! $out) {
$out = GroupPolicy :: where ( 'group_id' , 2 ) -> where ( 'policy_id' , $policy -> id) -> first ();
}
}
// Listing.php — добавить headerActions
-> headerActions ([
CreateAction :: make ( 'create' )
-> modalHeading ( 'Создать политику' )
-> form ([
TextInput :: make ( 'key' ) -> required () -> unique (),
TextInput :: make ( 'name' ) -> required (),
Select :: make ( 'category' )
-> options ( Policy :: pluck ( 'category' , 'category' ) -> unique ()),
TextInput :: make ( 'description' ),
]),
])
// В ToggleColumn::beforeStateUpdated()
Log :: info ( 'Policy changed' , [
'policy_id' => $record -> id,
'group_id' => 1 ,
'old_value' => $record -> admin ?-> value,
'new_value' => $state,
'user_id' => auth () -> id (),
]);
SELECT
p . key ,
p . name ,
p . category ,
MAX ( CASE WHEN gp . group_id = 1 THEN gp . value END ) as admin ,
MAX ( CASE WHEN gp . group_id = 2 THEN gp . value END ) as dealer,
MAX ( CASE WHEN gp . group_id = 3 THEN gp . value END ) as manager,
MAX ( CASE WHEN gp . group_id = 4 THEN gp . value END ) as production
FROM policies p
LEFT JOIN group_policies gp ON p . id = gp . policy_id
GROUP BY p . id , p . key , p . name , p . category
ORDER BY p . category , p . key ;
SELECT
u . id ,
u . email ,
u . name ,
g . name as group_name,
up . value
FROM users u
JOIN groups g ON u . group_id = g . id
JOIN user_policies up ON u . id = up . user_id
JOIN policies p ON up . policy_id = p . id
WHERE p . key = 'admin_can_view'
AND up . value = 1 ;
SELECT
category,
COUNT ( * ) as policies_count,
COUNT ( DISTINCT gp . group_id ) as groups_with_access
FROM policies p
LEFT JOIN group_policies gp ON p . id = gp . policy_id AND gp . value = 1
GROUP BY category
ORDER BY category;
┌─────────────────────────────────────────────────────────────────────────────┐
│ СВЯЗИ МОДУЛЯ ПОЛИТИК │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ │
│ │ policies │ │
│ └──────┬─────┘ │
│ │ │
│ ┌─────────────────────┼─────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ group_policies │ │ user_policies │ │ status_policies│ │
│ └───────┬────────┘ └───────┬────────┘ └───────┬────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ groups │ │ users │ │ statuses │ │
│ │ │ │ │ │ │ │
│ │ 1: Админ │ │ Админы (1) │ │ Политики │ │
│ │ 2: Дилер │ │ Менеджеры (3) │ │ статусов │ │
│ │ 3: Менеджер │ │ Производ. (4) │ │ (отдельная │ │
│ │ 4: Производство│ │ │ │ система) │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
│ ИСПОЛЬЗОВАНИЕ: │
│ ───────────────── │
│ ✓ check_access() — проверка прав пользователя │
│ ✓ Контроллеры — защита маршрутов │
│ ✓ Livewire — условное отображение элементов │
│ ✓ Blade — условия в шаблонах │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Документ подготовлен на основе анализа исходного кода проекта