Документация ЛК
Модули

Политики доступа

Модуль "Политики доступа"

Версия: 1.0
Дата: 2025-11-19
Статус: Реализован


Содержание

  1. Общее описание
  2. Текущая реализация
  3. Права доступа
  4. Описание полей
  5. UI/UX
  6. Бизнес-логика
  7. Выявленные проблемы
  8. Рекомендации

1. Общее описание

1.1 Предназначение модуля

Модуль "Политики доступа" — это центральный модуль системы авторизации. Он определяет:

  • Какие действия (политики) существуют в системе
  • Права по умолчанию для каждой группы пользователей
  • Индивидуальные права для конкретных пользователей

Это фундаментальный модуль, от которого зависят ВСЕ остальные модули системы!

1.2 Связь с другими модулями

МодульСвязьИспользование
Все модулиcheck_access()Проверка прав на действия
Группы пользователейgroup_policiesПрава по умолчанию для группы
Администраторыuser_policiesИндивидуальные права
Менеджерыuser_policiesИндивидуальные права (копируются из групповых)
Производствоuser_policiesИндивидуальные права
Дилерыgroup_policiesТолько групповые права!

1.3 Статистика

МетрикаЗначение
Всего политик57
Групповых политик124
Пользовательских политик924

1.4 Категории политик

КатегорияКоличество
Администраторы6
Дилеры (Компании)9
Дилеры (Менеджеры)10
Заказы7
Календарь1
Категории4
Менеджеры6
Новости4
Склады6
Товары4

2. Текущая реализация

2.1 Архитектура системы прав

┌─────────────────────────────────────────────────────────────────────────────┐
│                      СИСТЕМА АВТОРИЗАЦИИ (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 НАПРЯМУЮ                             │
│                (без индивидуальных прав!)                                   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.2 Структура БД

Таблица policies — Справочник политик

ПолеТипОписание
idbigintPK
keystringУникальный ключ политики
namestringНазвание для отображения
categorystringКатегория (для группировки)
descriptionstringОписание

Таблица group_policies — Групповые права

ПолеТипОписание
idbigintPK
group_idFKГруппа пользователей
policy_idFKПолитика
valuebooleanВключена/выключена

Таблица user_policies — Индивидуальные права

ПолеТипОписание
idbigintPK
user_idFKПользователь
policy_idFKПолитика
valuebooleanВключена/выключена

2.3 Файлы модуля

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

3. Права доступа

3.1 Проверка в контроллере

// PolicyController.php — ТОЛЬКО АДМИНИСТРАТОРЫ
public function index(Request $request)
{
    $user = $request->user();
    if (!$user or $user->group_id != 1)  // Жёсткая проверка
        abort(403);
    return view('templates.policies.table');
}

3.2 Матрица доступа к модулю

РольПросмотрРедактирование
Администратор
Менеджер
Производство
Дилер

4. Описание полей

4.1 Колонки таблицы

КолонкаОписаниеОсобенности
keyКлюч политикиПоиск
nameНазваниеПоиск
categoryКатегорияПоиск, фильтр, группировка
descriptionОписаниеПоиск
admin.valueПраво для AdminToggle
manager.valueПраво для МенеджерToggle
dealer.valueПраво для DealerToggle
production.valueПраво для ProductionToggle

5. UI/UX

5.1 Список политик

┌─────────────────────────────────────────────────────────────────────────────┐
│ Политики доступа                                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                              [Поиск...] [Фильтр 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 колонки с правами по группам

6. Бизнес-логика

6.1 Метод check_access() — КЛЮЧЕВОЙ!

// 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;
    }
}

6.2 Алгоритм работы прав

┌─────────────────────────────────────────────────────────────────────────────┐
│                      АЛГОРИТМ 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                                                 │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

6.3 Копирование прав при создании менеджера

При создании менеджера (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]
        );
    }
}

6.4 Автоматическое создание UserPolicy

При открытии карточки редактирования пользователя создаются записи 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]
        );
    }
}

6.5 Разница между группами

ГруппаИсточник правОсобенности
Admin (1)user_policiesИндивидуальные права
Дилер (2)group_policiesТОЛЬКО групповые! Нет индивидуальных
Менеджер (3)user_policiesКопируются из групповых при создании
Производство (4)user_policiesИндивидуальные права

6.6 Список всех политик

Администраторы

КлючОписание
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Может удалять позиции заказа

7. Выявленные проблемы

7.1 Критические

#ПроблемаФайлВлияние
Критических проблем не обнаружено

7.2 Средние

#ПроблемаОписаниеРешение
1Listing рендерит livewire.news.listingНеправильный viewЗаменить на livewire.base.listing
2Дилеры без индивидуальных правНельзя дать индивидуальные права дилеруДобавить поддержку user_policies для дилеров
3Жёсткая проверка group_id в контроллереНет политики доступа к модулюИспользовать check_access('policy_can_view')

7.3 Низкие

#ПроблемаОписание
4Нет CRUD для политикНельзя создать/редактировать/удалить политику через UI
5Нет аудита измененийНе логируется кто и когда менял права
6Нет экспортаНельзя выгрузить матрицу прав

8. Рекомендации

8.1 Приоритет: Высокий

Исправить view в Listing

// 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();
    }
}

8.2 Приоритет: Средний

Добавить CRUD для политик

// 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'),
        ]),
])

8.3 Приоритет: Низкий

Добавить аудит изменений прав

// В 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(),
]);

Приложение A: SQL для аналитики

Все политики с правами по группам

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;

Приложение B: Схема связей

┌─────────────────────────────────────────────────────────────────────────────┐
│                          СВЯЗИ МОДУЛЯ ПОЛИТИК                                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│                          ┌────────────┐                                     │
│                          │  policies  │                                     │
│                          └──────┬─────┘                                     │
│                                 │                                            │
│           ┌─────────────────────┼─────────────────────┐                     │
│           │                     │                     │                     │
│           ▼                     ▼                     ▼                     │
│  ┌────────────────┐    ┌────────────────┐    ┌────────────────┐            │
│  │ group_policies │    │ user_policies  │    │ status_policies│            │
│  └───────┬────────┘    └───────┬────────┘    └───────┬────────┘            │
│          │                     │                     │                      │
│          ▼                     ▼                     ▼                      │
│  ┌────────────────┐    ┌────────────────┐    ┌────────────────┐            │
│  │    groups      │    │     users      │    │   statuses     │            │
│  │                │    │                │    │                │            │
│  │ 1: Админ       │    │ Админы (1)     │    │ Политики       │            │
│  │ 2: Дилер       │    │ Менеджеры (3)  │    │ статусов       │            │
│  │ 3: Менеджер    │    │ Производ. (4)  │    │ (отдельная     │            │
│  │ 4: Производство│    │                │    │ система)       │            │
│  └────────────────┘    └────────────────┘    └────────────────┘            │
│                                                                              │
│  ИСПОЛЬЗОВАНИЕ:                                                              │
│  ─────────────────                                                           │
│  ✓ check_access() — проверка прав пользователя                              │
│  ✓ Контроллеры — защита маршрутов                                           │
│  ✓ Livewire — условное отображение элементов                                │
│  ✓ Blade — условия в шаблонах                                               │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Документ подготовлен на основе анализа исходного кода проекта

On this page

Модуль "Политики доступа"Содержание1. Общее описание1.1 Предназначение модуля1.2 Связь с другими модулями1.3 Статистика1.4 Категории политик2. Текущая реализация2.1 Архитектура системы прав2.2 Структура БДТаблица policies — Справочник политикТаблица group_policies — Групповые праваТаблица user_policies — Индивидуальные права2.3 Файлы модуля3. Права доступа3.1 Проверка в контроллере3.2 Матрица доступа к модулю4. Описание полей4.1 Колонки таблицы5. UI/UX5.1 Список политик6. Бизнес-логика6.1 Метод check_access() — КЛЮЧЕВОЙ!6.2 Алгоритм работы прав6.3 Копирование прав при создании менеджера6.4 Автоматическое создание UserPolicy6.5 Разница между группами6.6 Список всех политикАдминистраторыДилеры (Компании)Заказы7. Выявленные проблемы7.1 Критические7.2 Средние7.3 Низкие8. Рекомендации8.1 Приоритет: ВысокийИсправить view в ListingДобавить поддержку индивидуальных прав для дилеров8.2 Приоритет: СреднийДобавить CRUD для политик8.3 Приоритет: НизкийДобавить аудит изменений правПриложение A: SQL для аналитикиВсе политики с правами по группамПользователи с определённым правомСтатистика по категориямПриложение B: Схема связей