Symfony 4记住我的cookie没有设置

时间:2019-11-28 09:56:11

标签: php symfony authentication

我正在使用Symfony 4开发一个站点,我注意到记住我的功能无法正常工作(cookie根本没有设置)。我遵循了本教程:

https://symfony.com/doc/4.4/security/remember_me.html

我也阅读了很多类似的问题,但没有一个解决了我的问题。这是我的security.yaml配置:

security:
    encoders:
        App\Entity\User:
            algorithm: auto

    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: username
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: lazy
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            logout:
                path: app_logout
                # where to redirect after logout
                # target: app_any_route

            remember_me:
                secret:   '%kernel.secret%'
                lifetime: 604800 # 1 week in seconds
                path:     /

            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#firewalls-authentication

            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        # - { path: ^/admin, roles: ROLE_ADMIN }
        # - { path: ^/profile, roles: ROLE_USER }

这是我的表格:

<form method="post">
    <div class="form-group">
        <label for="inputUsername">Username</label>
        <input type="text" value="{{ last_username }}" name="username" id="inputUsername" class="form-control" required autofocus>
    </div>

    <div class="form-group">
        <label for="inputPassword">Password</label>
        <input type="password" name="password" id="inputPassword" class="form-control" required>
    </div>

    <div class="form-group">
        <div class="custom-control custom-checkbox">
            <input type="checkbox" name="_remember_me" class="custom-control-input" id="checkRememberMe">
            <label class="custom-control-label" for="checkRememberMe">Ricordami</label>
        </div>
    </div>

    <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">

    <button type="submit" class="btn btn-primary">Login</button>
</form>

我使用make:auth命令生成了身份验证:

<?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\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
    use TargetPathTrait;

    private $entityManager;
    private $urlGenerator;
    private $csrfTokenManager;
    private $passwordEncoder;

    public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
    {
        $this->entityManager = $entityManager;
        $this->urlGenerator = $urlGenerator;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->passwordEncoder = $passwordEncoder;
    }

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

    public function getCredentials(Request $request)
    {
        $credentials = [
            'username' => $request->request->get('username'),
            'password' => $request->request->get('password'),
            'csrf_token' => $request->request->get('_csrf_token'),
        ];
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['username']
        );

        return $credentials;
    }

    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if (!$this->csrfTokenManager->isTokenValid($token)) {
            throw new InvalidCsrfTokenException();
        }

        $user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);

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

        if (!$user->getEnabled()) {
            // fail authentication with a custom error
            throw new CustomUserMessageAuthenticationException('Utente non abilitato.');
        }

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
    }

    /**
     * Used to upgrade (rehash) the user's password automatically over time.
     */
    public function getPassword($credentials): ?string
    {
        return $credentials['password'];
    }

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

        return new RedirectResponse($this->urlGenerator->generate('homepage'));
    }

    protected function getLoginUrl()
    {
        return $this->urlGenerator->generate('app_login');
    }

    public function supportsRememberMe()
    {
        return true;
    }
}

我试图在源代码中对其进行调试,看来问题出在GuardAuthenticationListener类中:

// success!
$response = $this->guardHandler->handleAuthenticationSuccess($token, $request, $guardAuthenticator, $this->providerKey);
if ($response instanceof Response) {
    if (null !== $this->logger) {
        $this->logger->debug('Guard authenticator set success response.', ['response' => $response, 'authenticator' => \get_class($guardAuthenticator)]);
    }

    $event->setResponse($response); // <-- this is where the esecution STOPs
} else {
    if (null !== $this->logger) {
        $this->logger->debug('Guard authenticator set no success response: request continues.', ['authenticator' => \get_class($guardAuthenticator)]);
    }
}

// --> This line is NEVER CALLED
// attempt to trigger the remember me functionality
$this->triggerRememberMe($guardAuthenticator, $request, $token, $response);
// <-- This line is NEVER CALLED

如何触发triggerRememberMe方法?

编辑1 :由于以下原因,该执行在$event->setResponse($response)处停止了:

/**
 * Wraps a lazily computed response in a signaling exception.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
final class LazyResponseEvent extends RequestEvent
{
    private $event;

    public function __construct(parent $event)
    {
        $this->event = $event;
    }

    /**
     * {@inheritdoc}
     */
    public function setResponse(Response $response)
    {
        $this->stopPropagation();
        $this->event->stopPropagation();

        throw new LazyResponseException($response);
    }

    // [...]
}

1 个答案:

答案 0 :(得分:0)

已确认这是一个 bug ,并已在Symfony 4.4.1版中解决。如果您遇到此错误,请从4.4.0升级到4.4.1。

这是修复此问题的提交:https://github.com/symfony/symfony/pull/34627

这些是变更日志:https://symfony.com/blog/symfony-4-4-1-released