【问题标题】:Debugging the remember me in my symfony 6 application在我的 symfony 6 应用程序中调试记住我
【发布时间】:2022-07-14 04:15:37
【问题描述】:

我的 symfony 应用程序的记忆功能似乎无法正常工作。我已经关注了 Symfony 本身提供的资源here

无论如何,这是我的security.yaml 文件的一部分:

security:
    enable_authenticator_manager: true
    # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            form_login:
                login_path: /p/login
            entry_point: form_login
            # login_throttling:
            #     limiter: app.custom.limiter
            lazy: true
            provider: app_user_provider
            # https://symfony.com/doc/current/security/impersonating_user.html
            switch_user: true
            custom_authenticators:
                - App\Security\LoginFormAuthenticator
            logout:
                path: logout
                # where to redirect after logout
                # target: app_any_route
            remember_me:
                secret:   '%kernel.secret%'
                lifetime: 604800 # 1 week in seconds
                token_provider:
                    doctrine: true

我的LoginFormAuthenticator.php 文件:

<?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\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use Symfony\Component\RateLimiter\RateLimiterFactory;

class LoginFormAuthenticator extends AbstractAuthenticator
{
    use TargetPathTrait;

    public const LOGIN_ROUTE = 'login';

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

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

    public function supports(Request $request): ?bool
    {
        return self::LOGIN_ROUTE === $request->attributes->get('_route')
            && $request->isMethod('POST');
    }

    public function authenticate(Request $request): Passport
    {
        $email = $request->request->get('email');
        $password = $request->request->get('password');
        $csrfToken = $request->request->get('_csrf_token');

        return new Passport(
            new UserBadge($email),
            new PasswordCredentials($password),
            [
                new CsrfTokenBadge('authenticate', $csrfToken),
                new RememberMeBadge()
            ],
        );
    }

    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(['email' => $credentials['email']]);

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

        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, string $providerKey): ?Response
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }

        return new RedirectResponse($this->urlGenerator->generate('feed', ['page_num' => 1]));
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {

        $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);

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

    protected function getLoginUrl()
    {
        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }
}

使用学说作为令牌提供者创建的数据库架构:

用户登录但一个小时后自动注销(我相信)这很烦人。即使在 security.yaml 文件中指定了 1 周。


更新 通过 github (here) 阅读线程后,这种方法似乎不可行。我们应该使用什么替代方法来让我们的用户在我们在security.yaml 文件中注明的指定持续时间内保持登录状态?

考虑一下,如果我们使用 cookie 或常规会话进行用户登录,由于cache:clear 功能,每次我们部署时每个用户都会被注销。

【问题讨论】:

  • 您是否在登录表单中添加了checkbox?或者试试always_remember_me: true?条目是否以正确的日期添加到数据库中?
  • 是的,复选框是登录表单的一部分。日期看起来正确。我没有打开总是记得我,因为那不是我们想做的事情。
  • 我还在调试中确认,当复选框被选中时,它显示为“on”,并且 RememberMeBadge 显示在身份验证器中。嗯'
  • 您是否尝试过基于 cookie 而不是基于 db?只是为了调试.. 我确实看到了一个 issue 发布但那是前一阵子了,可能仍然是一个错误?
  • 您在选中复选框后登录后是否有REMEMBERME cookie?您的复选框名称是否正是 _remember_me

标签: symfony session


【解决方案1】:

转到用户实体并找到getUserIdentyfier() 函数。确保这会返回电子邮件。

属性:电子邮件

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-03
  • 2010-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-12
  • 1970-01-01
相关资源
最近更新 更多