bp/app/Filters/RoleFilter.php

120 lines
4.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Filters;
use App\Services\AccessService;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
/**
* RoleFilter - Фильтр проверки ролей и прав доступа
*
* Применяется к маршрутам для проверки прав доступа на уровне роутинга.
*
* Использование в роутах:
* $routes->get('/admin/users', 'Users::index', ['filter' => 'role:admin']);
* $routes->get('/admin/settings', 'Settings::index', ['filter' => 'role:owner']);
*/
class RoleFilter implements FilterInterface
{
/**
* Проверка доступа перед выполнением запроса
*
* @param RequestInterface $request
* @param array|null $arguments Аргументы из маршрута (роли, разрешения)
* @return ResponseInterface|null
*/
public function before(RequestInterface $request, $arguments = null)
{
// Если фильтр вызван без аргументов - пропускаем
if ($arguments === null) {
return null;
}
$access = AccessService::getInstance();
// Разбор аргументов
// Формат: 'role:admin,manager' или 'role:system:superadmin' или 'permission:manage_users:users'
// Проверка системных ролей (system: prefix)
if (is_string($arguments) && str_starts_with($arguments, 'role:system:')) {
$roles = explode(',', substr($arguments, 13)); // 13 = длина 'role:system:'
$roles = array_map('trim', $roles);
// Для системных ролей НЕ требуется авторизация в организации
if (!$access->isSystemRole($roles)) {
return $this->forbiddenResponse();
}
return null;
}
// Проверка организационных ролей
if (is_string($arguments) && str_starts_with($arguments, 'role:')) {
$roles = explode(',', substr($arguments, 5));
$roles = array_map('trim', $roles);
// Проверка авторизации в организации
if (!$access->isAuthenticated()) {
// Если пользователь не авторизован в организации - редирект на выбор организации
return redirect()->to('/organizations');
}
if (!$access->isRole($roles)) {
return $this->forbiddenResponse();
}
}
if (is_string($arguments) && str_starts_with($arguments, 'permission:')) {
// Проверка авторизации в организации для разрешений
if (!$access->isAuthenticated()) {
return redirect()->to('/organizations');
}
$parts = explode(':', substr($arguments, 11));
if (count($parts) >= 2) {
$permission = $parts[0];
$resource = $parts[1] ?? '*';
if (!$access->can($permission, $resource)) {
return $this->forbiddenResponse();
}
}
}
return null;
}
/**
* Обработка после выполнения запроса
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param array|null $arguments
* @return void
*/
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
// Ничего не делаем после
}
/**
* Возврат ответа "Доступ запрещён"
*
* @return ResponseInterface
*/
private function forbiddenResponse(): ResponseInterface
{
// Проверяем, AJAX ли это запрос
if (service('request')->isAJAX()) {
return service('response')
->setStatusCode(403)
->setJSON(['error' => 'Доступ запрещён']);
}
// Для обычных запросов - редирект с сообщением
session()->setFlashdata('error', 'У вас нет прав для выполнения этого действия');
return redirect()->to('/');
}
}