101 lines
3.5 KiB
PHP
101 lines
3.5 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();
|
||
|
||
// Проверка авторизации в организации
|
||
if (!$access->isAuthenticated()) {
|
||
// Если пользователь не авторизован в организации - редирект на выбор организации
|
||
return redirect()->to('/organizations');
|
||
}
|
||
|
||
// Разбор аргументов
|
||
// Формат: 'role:admin,manager' или 'permission:manage_users:users'
|
||
if (is_string($arguments) && str_starts_with($arguments, 'role:')) {
|
||
$roles = explode(',', substr($arguments, 5));
|
||
$roles = array_map('trim', $roles);
|
||
|
||
if (!$access->isRole($roles)) {
|
||
return $this->forbiddenResponse();
|
||
}
|
||
}
|
||
|
||
if (is_string($arguments) && str_starts_with($arguments, 'permission:')) {
|
||
$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('/');
|
||
}
|
||
}
|