added permission caching (#3877)
This commit is contained in:
@@ -16,11 +16,11 @@ use App\Event\PermissionSectionsEvent;
|
||||
use App\Event\PermissionsEvent;
|
||||
use App\Form\RoleType;
|
||||
use App\Model\PermissionSection;
|
||||
use App\Repository\RolePermissionRepository;
|
||||
use App\Repository\RoleRepository;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Security\RolePermissionManager;
|
||||
use App\Security\RoleService;
|
||||
use App\User\PermissionService;
|
||||
use App\Utils\PageSetup;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@@ -227,7 +227,7 @@ final class PermissionController extends AbstractController
|
||||
|
||||
#[Route(path: '/roles/{id}/{name}/{value}/{csrfToken}', name: 'admin_user_permission_save', methods: ['POST'])]
|
||||
#[IsGranted('role_permissions')]
|
||||
public function savePermission(Role $role, string $name, bool $value, string $csrfToken, RolePermissionRepository $rolePermissionRepository, CsrfTokenManagerInterface $csrfTokenManager): Response
|
||||
public function savePermission(Role $role, string $name, bool $value, string $csrfToken, PermissionService $permissionService, CsrfTokenManagerInterface $csrfTokenManager): Response
|
||||
{
|
||||
if (!$this->isCsrfTokenValid(self::TOKEN_NAME, $csrfToken)) {
|
||||
throw new BadRequestHttpException('Invalid CSRF token');
|
||||
@@ -242,7 +242,7 @@ final class PermissionController extends AbstractController
|
||||
}
|
||||
|
||||
try {
|
||||
$permission = $rolePermissionRepository->findRolePermission($role, $name);
|
||||
$permission = $permissionService->findRolePermission($role, $name);
|
||||
if (null === $permission) {
|
||||
$permission = new RolePermission();
|
||||
$permission->setRole($role);
|
||||
@@ -250,7 +250,7 @@ final class PermissionController extends AbstractController
|
||||
}
|
||||
$permission->setAllowed($value);
|
||||
|
||||
$rolePermissionRepository->saveRolePermission($permission);
|
||||
$permissionService->saveRolePermission($permission);
|
||||
|
||||
// refreshToken instead of getToken for more security but worse UX
|
||||
// fast clicking with slow response times would fail, as the token cannot be replaced fast enough
|
||||
|
||||
@@ -18,7 +18,7 @@ use Doctrine\ORM\EntityRepository;
|
||||
*/
|
||||
class RolePermissionRepository extends EntityRepository
|
||||
{
|
||||
public function saveRolePermission(RolePermission $permission)
|
||||
public function saveRolePermission(RolePermission $permission): void
|
||||
{
|
||||
$entityManager = $this->getEntityManager();
|
||||
$entityManager->persist($permission);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
namespace App\Security;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Repository\RolePermissionRepository;
|
||||
use App\User\PermissionService;
|
||||
|
||||
final class RolePermissionManager
|
||||
{
|
||||
@@ -29,11 +29,11 @@ final class RolePermissionManager
|
||||
private bool $isInitialized = false;
|
||||
|
||||
/**
|
||||
* @param RolePermissionRepository $repository
|
||||
* @param PermissionService $service
|
||||
* @param array<string, array<string, bool>> $permissions as defined in kimai.yaml
|
||||
* @param array<string, bool> $permissionNames as defined in kimai.yaml
|
||||
*/
|
||||
public function __construct(private RolePermissionRepository $repository, private array $permissions, private array $permissionNames)
|
||||
public function __construct(private PermissionService $service, private array $permissions, private array $permissionNames)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ final class RolePermissionManager
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->repository->getAllAsArray() as $item) {
|
||||
foreach ($this->service->getPermissions() as $item) {
|
||||
$perm = (string) $item['permission'];
|
||||
$role = (string) $item['role'];
|
||||
|
||||
|
||||
62
src/User/PermissionService.php
Normal file
62
src/User/PermissionService.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\User;
|
||||
|
||||
use App\Entity\Role;
|
||||
use App\Entity\RolePermission;
|
||||
use App\Repository\RolePermissionRepository;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
|
||||
/**
|
||||
* Caches permissions, which rarely change once Kimai is setup.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class PermissionService
|
||||
{
|
||||
/**
|
||||
* @var null|array<int, array<string, string|bool>>
|
||||
*/
|
||||
private ?array $cacheAll = null;
|
||||
|
||||
public function __construct(
|
||||
private RolePermissionRepository $repository,
|
||||
private CacheInterface $cache
|
||||
) {
|
||||
}
|
||||
|
||||
public function saveRolePermission(RolePermission $permission): void
|
||||
{
|
||||
$this->repository->saveRolePermission($permission);
|
||||
$this->cache->delete('permissions');
|
||||
}
|
||||
|
||||
public function findRolePermission(Role $role, string $permission): ?RolePermission
|
||||
{
|
||||
return $this->repository->findRolePermission($role, $permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string, string|bool>>
|
||||
*/
|
||||
public function getPermissions(): array
|
||||
{
|
||||
if ($this->cacheAll === null) {
|
||||
$this->cacheAll = $this->cache->get('permissions', function (ItemInterface $item) {
|
||||
$item->expiresAfter(86400); // one day
|
||||
|
||||
return $this->repository->getAllAsArray();
|
||||
});
|
||||
}
|
||||
|
||||
return $this->cacheAll;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user