120 lines
4.4 KiB
PHP
120 lines
4.4 KiB
PHP
<?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('/');
|
|
}
|
|
}
|