Update "User authentication" customization example (5.0)#3087
Update "User authentication" customization example (5.0)#3087adriendupuis wants to merge 16 commits into5.0from
Conversation
Preview of modified filesPreview of modified Markdown: |
Method App\EventSubscriber\InteractiveLoginSubscriber::__construct() has parameter $userMap with no value type specified in iterable type array.
| $ibexaUser = $this->userService->loadUserByLogin($userLogin); | ||
| $event->getAuthenticationToken()->setUser(new User($ibexaUser)); |
There was a problem hiding this comment.
I could use Ibexa\Core\MVC\Symfony\Security\User\UsernameProvider::loadUserByIdentifier() to get the repo user already wrapped:
| $ibexaUser = $this->userService->loadUserByLogin($userLogin); | |
| $event->getAuthenticationToken()->setUser(new User($ibexaUser)); | |
| $ibexaUser = $this->userNameProvider->loadUserByIdentifier($userLogin); | |
| $event->getAuthenticationToken()->setUser($ibexaUser); |
See #3088 for complete integration of this idea.
Pros:
- Relies on the user provider it replaces
Cons:
- Hides
Ibexa\Core\MVC\Symfony\Security\Userusage
it's still out of Contracts namespace.
|
Is the SecurityEvents::INTERACTIVE_LOGIN the correct event now? I believe this fires after https://github.com/ibexa/core/blob/main/src/lib/MVC/Symfony/Security/Authentication/EventSubscriber/OnAuthenticationTokenCreatedRepositoryUserSubscriber.php which sets the repository user. Also I see no logic anymore that sets a UserWrapped for the InteractiveLogin event to use. I have a working method for myself now. That is to listen for a "AuthenticationTokenCreatedEvent" of our own and create and set a wrapped user there. Also need to make sure that your custom userprovider refreshes as wrapped user properly considering both the apiUser and the customUser Not sure if this helps you at all or not. Also note i included a switchuserlistenr here too as it is broken too by default and will not work with wrapped users otherwise. I have removed some login from the below to post here so code may not run as is. <?php
declare(strict_types=1);
namespace App\Security\EventSubscriber;
use App\Entity\AppUser;
use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Core\Repository\Repository;
use Ibexa\Contracts\Core\Repository\Values\User\User;
use Ibexa\Core\MVC\Symfony\Security\UserWrapped;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Http\Event\AuthenticationTokenCreatedEvent;
final readonly class AuthenticationTokenCreatedSubscriber implements EventSubscriberInterface
{
public function __construct(
private Repository $repository,
private PermissionResolver $permissionResolver,
) {
}
public static function getSubscribedEvents(): array
{
return [
AuthenticationTokenCreatedEvent::class => 'onAuthenticationTokenCreated',
];
}
public function onAuthenticationTokenCreated(AuthenticationTokenCreatedEvent $event): void
{
$user = $event->getAuthenticatedToken()->getUser();
if (!$user instanceof AppUser) {
return;
}
$apiUser = $user->getIbexaUserId() ? $this->repository->sudo(
function (Repository $repository) use ($user) {
try {
return $repository->getUserService()->loadUser($user->getIbexaUserId());
} catch (\Exception) {
return null;
}
}
) : $this->repository->sudo(
function (Repository $repository) use ($user) {
try {
return $repository->getUserService()->loadUserByLogin($user->getUserIdentifier());
} catch (\Exception) {
return null;
}
}
);
if ($apiUser instanceof User) {
$this->permissionResolver->setCurrentUserReference($apiUser);
$event->getAuthenticatedToken()->setUser(new UserWrapped($user, $apiUser));
}
}
}In UserProvider public function refreshUser(UserInterface $user): UserInterface
{
if ($user instanceof UserWrapped && $user->getWrappedUser() instanceof AppUser) {
$user = $this->loadUserByIdentifier($user->getWrappedUser()->getUserIdentifier());
} else {
$user = $this->loadUserByIdentifier($user->getUserIdentifier());
}
/** @var AppUser $user */
$apiUser = $user->getIbexaUserId() ? $this->repository->sudo(
fn (Repository $repository) => $repository->getUserService()->loadUser($user->getIbexaUserId())
) : $this->repository->sudo(
fn (Repository $repository) => $repository->getUserService()->loadUserByLogin(
$user->getUserIdentifier()
)
);
return new UserWrapped($user, $apiUser);
}<?php
declare(strict_types=1);
namespace App\Security\EventSubscriber;
use App\Entity\AppUser;
use Doctrine\ORM\EntityManagerInterface;
use Ibexa\Contracts\Core\Repository\Repository;
use Ibexa\Core\MVC\Symfony\Security\UserWrapped;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
use Symfony\Component\Security\Http\SecurityEvents;
final readonly class SwitchUserEventSubscriber implements EventSubscriberInterface
{
public function __construct(
private Repository $repository,
) {
}
public static function getSubscribedEvents(): array
{
return [
SecurityEvents::SWITCH_USER => ['onSwitchUser', 0],
];
}
public function onSwitchUser(SwitchUserEvent $event): void
{
$token = $event->getToken();
if (
$token instanceof SwitchUserToken
&& $token->getUser() instanceof AppUser
&& $token->getOriginalToken()->getUser() instanceof UserWrapped
&& $token->getOriginalToken()->getUser()->getWrappedUser() instanceof AppUser
) {
$currentUsername = $token->getOriginalToken()->getUserIdentifier();
$targetUsername = $token->getUserIdentifier();
$user = $token->getUser();
$apiUser = $user->getIbexaUserId() ? $this->repository->sudo(
function (Repository $repository) use ($user) {
try {
return $repository->getUserService()->loadUser($user->getIbexaUserId());
} catch (\Exception) {
return null;
}
}
) : $this->repository->sudo(
function (Repository $repository) use ($user) {
try {
return $repository->getUserService()->loadUserByLogin($user->getUserIdentifier());
} catch (\Exception) {
return null;
}
}
);
$wrappedUser = new UserWrapped($user, $apiUser);
$token->setUser($wrappedUser);
}
$event->getRequest()->getSession()->migrate();
}
} |
code_samples/ change report
|
|



Update for DXP 5.0 SF 7.3 since ibexa/core#411 and other big changes
Related RP: #3086
Checklist