Symfony 4 - Пользовательский GuardAuthenticator не устанавливает файл cookie «Запомнить меня»

Я создаю собственный GuardAuthenticator для входа в систему с токеном по определенному маршруту. В соответствии с документация, если supportsRememberMe() возвращает true и remember_me активирован в брандмауэре, файл cookie «запомнить меня» должен быть установлен, но это не так (хотя он установлен, если я использую аутентификацию с помощью формы на другом маршруте).

Маршрут:

/**
 * @Route("/login/token/{id}/{token}/{force}", defaults = {"force"=0}, name = "login_token")
 */
public function loginToken()
{

}

GuardAuthenticator:

<?php


namespace App\Security;


use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class TokenLoginAuthenticator extends AbstractGuardAuthenticator
{
    use TargetPathTrait;

    private $em;
    private $force;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function supports(Request $request)
    {
        return 'login_token' === $request->attributes->get('_route') && $request->isMethod('GET');
    }


    public function getCredentials(Request $request)
    {
        $credentials = [
            'id' => $request->attributes->get('id'),
            'token' => $request->attributes->get('token')
        ];

        $this->force = $request->attributes->get('force');

        return $credentials;
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $user = $this->em->getRepository(User::class)->find($credentials['id']);

        if (!$user) {
            // fail authentication with a custom error
            throw new CustomUserMessageAuthenticationException('No user found.');
        }

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        if ($user->getToken() === $credentials['token']) {
            return true;
        }
        throw new HttpException(403, "Forbidden");
    }


    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        throw new HttpException(403, "Forbidden");
    }

    public function start(Request $request, AuthenticationException $authException = null)
    {
    }

    public function supportsRememberMe()
    {
        return true;
    }
}

Конфиг безопасности:

security:
    encoders:
        App\Entity\User:
            id: 'App\Security\PasswordEncoder'

    providers:
        in_memory: { memory: ~ }
        orm:
            entity:
                class: App\Entity\User
                property: email

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            anonymous: true
            form_login:
                login_path: login
                check_path: login
                provider: orm
                csrf_token_generator: security.csrf.token_manager
                default_target_path: homepage

            logout:
                path:   /logout
                target: /

            remember_me:
                secret:   '%kernel.secret%'
                lifetime: 604800 # 1 week in seconds
                path: /
                # by default, the feature is enablered by checking a
                # checkbox in the login form (see below), uncomment the
                # following line to always enable it.
                # always_remember_me: true

            guard:
                provider: orm
                authenticators:
                    - App\Security\TokenLoginAuthenticator
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
0
924
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Cookie-файл «Запомнить меня» будет установлен, если будет выполнено все из следующего:

  • Метод supportsRememberMe() возвращает true.
  • Клавиша remember_me в брандмауэре настроена.
  • Параметр (по умолчанию) _remember_me отправляется в запросе. Обычно это делается с помощью флажка _remember_me в форме входа (но его можно отправить как параметр URL-адреса (?_remember_me=1), или мы можем настроить ключ брандмауэра remember_me на always_remember_me.
  • Метод onAuthenticationSuccess() возвращает объект Response.

В Symfony 5.2.6 не забудьте добавить новый RememberMeBadge() в функцию аутентификации:

use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;

class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
    public function authenticate(Request $request): PassportInterface
    {
        $email = $request->request->get('email', '');

        $request->getSession()->set(Security::LAST_USERNAME, $email);

        return new Passport(
            new UserBadge($email),
            new PasswordCredentials($request->request->get('password', '')),
            [
                new CsrfTokenBadge('authenticate', $request->get('_csrf_token')),
                new RememberMeBadge(),
            ]
        );
    }
}

Другие вопросы по теме