Symfony 身份验证器未正确验证身份验证器在重定向后不会保留用户

Posted

技术标签:

【中文标题】Symfony 身份验证器未正确验证身份验证器在重定向后不会保留用户【英文标题】:Symfony authenticator dosnt authenticat properly authenticator dosnt keep user after redirecting 【发布时间】:2021-09-04 06:14:04 【问题描述】:

最近我陷入了一个错误,我不知道为什么它不起作用我希望你们有一个想法。

所以重点是我想为我的管理员创建一个登录名,所以我创建了实体 \App\Entity\Admin、控制器 AdminController 和身份验证器 AdminLoginAuthentication 并且它在安全配置中 guardaccess-point

当我通过 admin.1@yahoo.com 登录时,登录成功重定向admin_dashboard但关键是身份验证器不会保留凭据,并且访问点会重新将管理员重定向到登录。

另外,我看到了这个Symfony 4 login form : authenticating successfully, but authentication immediately lost after redirect,但它不起作用。

Here you can see in login it should be Annonymous and it is (pic)

Here you can see that I'm logged in but still I'm anonymous (pic)

Here is Symfony-profiler you can see that in login successfully authenticate (pic)

But after successfully authenticate and redirect to dashboard roll become anonymous (pic)

并且由于访问点

重定向回登录

为了更好地理解,请查看图片

这是我的 security.yaml

security:
    encoders:
        App\Entity\Admin:
            algorithm: bcrypt

    providers:
        admin_provider:
            entity:
                class: App\Entity\Admin
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        artist:
            anonymous: ~
            pattern: ^/admin
            provider: admin_provider
            guard:
                authenticators:
                    - App\Security\AdminLoginAuthenticator
            logout:
                path: admin_logout
    access_control:
        -  path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY 
        -  path: ^/admin/, roles: ROLE_ADMIN 

这是我的 登录表单,来自 Symfony FormBuilder - AdminLoginType

namespace App\Form\Admin;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;

class AdminLoginType extends AbstractType

    public function buildForm(FormBuilderInterface $builder, array $options)
    
        $builder
            ->add('username', EmailType::class, [
                'attr' => [
                    'class' => 'form-control form-control-solid h-auto py-6 px-6 rounded-lg',
                    'placeholder' => 'Username',
                    'autocomplete' => 'off',
                ]
            ])
            ->add('password', PasswordType::class, [
                'attr' => [
                    'class' => 'form-control form-control-solid h-auto py-6 px-6 rounded-lg',
                    'placeholder' => 'Password',
                ]
            ])
            ->add('submit', SubmitType::class, [
                'label' => 'Sign in',
                'attr' => [
                    'class' => 'btn btn-primary font-weight-bolder font-size-h6 px-8 py-4 my-3 mr-3',
                ]
            ]);
    

这是我的身份验证器 AdminLoginAuthenticator

namespace App\Security;

use App\Entity\Admin;
use App\Form\Artist\AdminLoginType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\FormFactoryInterface;
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\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class AdminLoginAuthenticator extends AbstractFormLoginAuthenticator

    use TargetPathTrait;

    public const LOGIN_ROUTE = 'Admin_login';

    private $entityManager;

    private $urlGenerator;

    private $passwordEncoder;

    private $formFactory;

    public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, UserPasswordEncoderInterface $passwordEncoder, FormFactoryInterface $formFactory)
    
        $this->entityManager = $entityManager;
        $this->urlGenerator = $urlGenerator;
        $this->passwordEncoder = $passwordEncoder;
        $this->formFactory = $formFactory;
    

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

    public function getCredentials(Request $request)
    
        $form = $this->formFactory->create(AdminLoginType::class);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) 
            $credentials = $form->getData();

            $request->getSession()->set(
                Security::LAST_USERNAME,
                $credentials['username']
            );

            return $credentials;
        

        throw new CustomUserMessageAuthenticationException("Custom User Message Authentication Exception");
    

    public function getUser($credentials, UserProviderInterface $userProvider)
    
        $user = $this->entityManager->getRepository(Admin::class)->findOneBy(['email' => $credentials['username']]);

        if (!$user) 
            throw new CustomUserMessageAuthenticationException("Custom User Message Authentication Exception");
        

        return $user;
    

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

        return false;
    

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    
        return new RedirectResponse($this->urlGenerator->generate('admin_dashboard'));
    

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

这是我的AdminController

namespace App\Controller\Admin;

use App\Form\Artist\AdminForgetType;
use App\Form\Artist\AdminLoginType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

/**
 * @Route("/admin")
 */
class AdminController extends AbstractController

    /**
     * @Route("/", name="admin_index")
     */
    public function index()
    
         if ($this->getUser())
             return $this->redirectToRoute('admin_dashboard');

        return $this->redirectToRoute("admin_login");
    

    /**
     * @Route("/login", name="admin_login")
     */
    public function login(AuthenticationUtils $authenticationUtils): Response
    
        // get the login error if there is one
        $error = $authenticationUtils->getLastAuthenticationError();
        // last username entered by the user
        $lastUsername = $authenticationUtils->getLastUsername();

        $admin_login_form = $this->createForm(ArtistLoginType::class, ["username" => $lastUsername]);
        $admin_forget_form = $this->createForm(ArtistForgetType::class);

        return $this->render('admin/login.html.twig', [
            'artist_login_form' => $admin_login_form->createView(),
            'artist_forget_form' => $admin_forget_form->createView(),
            'error' => $error,
        ]);
    

    /**
     * @Route("/logout", name="admin_logout")
     */
    public function logout()
    
        throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
    

这是我的实体\App\Entity\Admin\App\Entity\User扩展

namespace App\Entity;

use App\Repository\AdminRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=AdminRepository::class)
 */
class Admin extends User

    public function getRoles(): array
    
        $roles = parent::getRoles();
        $roles[] = 'ROLE_ADMIN';

        return array_unique($roles);
    

这是 \App\Entity\User 从我的界面 UserModelInterface

实现
namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\MappedSuperclass()
 */
class User implements UserModelInterface

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=32)
     */
    protected $name;

    /**
     * @ORM\Column(type="string", length=32)
     */
    protected $family;

    /**
     * @ORM\Column(type="string", length=180)
     */
    protected $email;

    /**
     * @ORM\Column(type="string", length=255)
     */
    protected $password;

    /**
     * @ORM\Column(type="date")
     */
    protected $birth;

    /**
     * @ORM\Column(type="integer")
     */
    protected $profile;

    /**
     * @ORM\Column(type="json")
     */
    protected $last_5_passwords = [];

    /**
     * @ORM\Column(type="datetime")
     */
    protected $last_password_update;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $register_date;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $update_date;

    /**
     * @ORM\Column(type="json")
     */
    protected $roles = [];

    public function getId(): ?int
    
        return $this->id;
    

    /**
     * @see UserModelInterface
     */
    public function getName(): ?string
    
        return $this->name;
    

    /**
     * @see UserModelInterface
     */
    public function setName(string $name): self
    
        $this->name = $name;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getFamily(): ?string
    
        return $this->family;
    

    /**
     * @see UserModelInterface
     */
    public function setFamily(string $family): self
    
        $this->family = $family;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getEmail(): ?string
    
        return $this->email;
    

    /**
     * @see UserModelInterface
     */
    public function setEmail(string $email): self
    
        $this->email = $email;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getPassword(): ?string
    
        return $this->password;
    

    /**
     * @see UserModelInterface
     */
    public function setPassword(string $password): self
    
        $this->password = $password;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getBirth(): ?\DateTimeInterface
    
        return $this->birth;
    

    /**
     * @see UserModelInterface
     */
    public function setBirth(\DateTimeInterface $birth): self
    
        $this->birth = $birth;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getProfile(): ?int
    
        return $this->profile;
    

    /**
     * @see UserModelInterface
     */
    public function setProfile(int $profile): self
    
        $this->profile = $profile;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getLast5Passwords(): ?array
    
        return $this->last_5_passwords;
    

    /**
     * @see UserModelInterface
     */
    public function setLast5Passwords(array $last_5_passwords): self
    
        $this->last_5_passwords = $last_5_passwords;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getLastPasswordUpdate(): ?\DateTimeInterface
    
        return $this->last_password_update;
    

    /**
     * @see UserModelInterface
     */
    public function setLastPasswordUpdate(\DateTimeInterface $last_password_update): self
    
        $this->last_password_update = $last_password_update;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getRegisterDate(): ?\DateTimeInterface
    
        return $this->register_date;
    

    /**
     * @see UserModelInterface
     */
    public function setRegisterDate(\DateTimeInterface $register_date): self
    
        $this->register_date = $register_date;

        return $this;
    

    /**
     * @see UserModelInterface
     */
    public function getUpdateDate(): ?\DateTimeInterface
    
        return $this->update_date;
    

    /**
     * @see UserModelInterface
     */
    public function setUpdateDate(\DateTimeInterface $update_date): self
    
        $this->update_date = $update_date;

        return $this;
    

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    

    /**
     * @see UserModelInterface
     */
    public function setRoles(array $roles): self
    
        $this->roles = $roles;

        return $this;
    

    /**
     * @see UserInterface
     */
    public function getSalt()
    
        return null;
    

    /**
     * @see UserInterface
     */
    public function getUsername()
    
        return $this->email;
    

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    
        $this->password = null;
    

这是 UserModelInterfaceUserInterface

扩展
namespace App\Entity;

use Symfony\Component\Security\Core\User\UserInterface;

interface UserModelInterface extends UserInterface

    /**
     * @return string
     */
    public function getName();

    /**
     * @param string $name
     * @return self
     */
    public function setName(string $name);

    /**
     * @return string
     */
    public function getFamily();

    /**
     * @param string $family
     *
     * @return self
     */
    public function setFamily(string $family);

    /**
     * @return string
     */
    public function getEmail();

    /**
     * @param string $email
     * @return self
     */
    public function setEmail(string $email);

    /**
     * @return string
     */
    public function getPassword();

    /**
     * @param string $password
     * @return self
     */
    public function setPassword(string $password);

    /**
     * @return \DateTimeInterface
     */
    public function getBirth();

    /**
     * @param \DateTimeInterface $birth
     * @return self
     */
    public function setBirth(\DateTimeInterface $birth);

    /**
     * @return int
     */
    public function getProfile();

    /**
     * @param int $profile
     * @return self
     */
    public function setProfile(int $profile);

    /**
     * @return array
     */
    public function getLast5Passwords();

    /**
     * @param array $last_5_passwords
     * @return self
     */
    public function setLast5Passwords(array $last_5_passwords);

    /**
     * @return \DateTimeInterface
     */
    public function getLastPasswordUpdate();

    /**
     * @param \DateTimeInterface $last_password_update
     * @return self
     */
    public function setLastPasswordUpdate(\DateTimeInterface $last_password_update);

    /**
     * @return \DateTimeInterface
     */
    public function getRegisterDate();

    /**
     * @param \DateTimeInterface $register_date
     * @return self
     */
    public function setRegisterDate(\DateTimeInterface $register_date);

    /**
     * @return \DateTimeInterface
     */
    public function getUpdateDate();

    /**
     * @param \DateTimeInterface $update_date
     */
    public function setUpdateDate(\DateTimeInterface $update_date);

    /**
     * @param array $roles
     *
     * @return mixed
     */
    public function setRoles(array $roles);

【问题讨论】:

你尝试过什么调试?您链接的问题听起来非常像您的问题,对吧?那么“it doesn't work”是什么意思——你从这些答案中尝试了什么,发生了什么?你是否至少消除了一些基本的东西,比如确保你的会话正常工作?在这里转储大量代码而不描述您尝试解决的问题或调查您的问题并不容易让任何人提供帮助。考虑尝试创建一个minimal, complete, and verifiable example。 【参考方案1】:

我认为您需要在 security.yaml 文件中进行更改 访问控制: - 路径:^/admin/login,角色:IS_AUTHENTICATED_ANONYMOUSLY

到 访问控制: - 路径:^/admin/login,角色:ROLE_ADMIN

【讨论】:

【参考方案2】:

所以在这种情况下,我发现在您的 \App\Entity\User 中,从 UserInterface eraseCredentials() 方法实现 您不应该将密码设为 null 或为空 .

当我们有另一个像 plainPassword 这样的密码属性时,我们应该在 eraseCredentials() 上将 plainPassword 设为 null

【讨论】:

以上是关于Symfony 身份验证器未正确验证身份验证器在重定向后不会保留用户的主要内容,如果未能解决你的问题,请参考以下文章

XCTest 中未保留经过身份验证的 Vapor 会话

Symfony PHPUnit 测试不验证用户

有没有一种正确的方法可以在 symfony 中使用 SwiftMailer 包将 NTLM 身份验证类型添加到 SwiftMailer 中?

Symfony 5.3 新身份验证不保留我的身份验证

Amplify add storage - 允许未经身份验证的用户需要进行身份验证配置,但未正确配置

Instagram 客户端身份验证在重定向后缺少#access_token