简体   繁体   English

onAuthenticationSuccess 重定向后 Symfony 用户丢失

[英]Symfony User lost after onAuthenticationSuccess redirect

Have followed the instructions on: https://symfony.com/doc/current/security/form_login_setup.html , and in step 3 (in the onAuthenticationSuccess method) - if I leave the Exception in, the profiler bar shows the user logged in, however if I comment in the redirect, the user is lost on the following page.已按照以下说明操作: https://symfony.com/doc/current/security/form_login_setup.html ,并在第 3 步(在onAuthenticationSuccess方法中) - 如果我将 Exception 保留,则分析器栏会显示用户已登录,但是如果我在重定向中发表评论,用户将在下一页中丢失。 Sessions are set up and working as pdo.会话被设置并作为 pdo 工作。

Anyone have any ideas?谁有想法?

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\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
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\Http\Util\TargetPathTrait;

class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
    use TargetPathTrait;

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

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

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

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

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

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

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user)
    {
        // Check the user's password or other credentials and return true or false
        // If there are no credentials to check, you can just return true
        return true;
        //throw new \Exception('TODO: check the credentials inside '.__FILE__);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }
        //throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
        return new RedirectResponse($this->urlGenerator->generate('app_dashboard'));

    }

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

DashboardController.php

<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class DashboardController extends AbstractController
{
    private $session;
    function __construct(SessionInterface $session)
    {
        $this->session = $session;
    }
    /**
     * @Route("/dashboard", name="app_dashboard")
     */ 
    function dashboard()
    {
        return $this->render('account/dashboard.html.twig', []);
    }
}

security.yaml

security:
    providers:
        users:
            entity:
                class: 'App\Entity\User'
                property: 'email'
    encoders:
        App\Entity\User:
            algorithm: 'auto'
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: lazy
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            logout:
                path: app_logout
    access_control:
        - { path: ^/dashboard, roles: ROLE_USER }

User.php

<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
 * User
 *
 * @ORM\Table(name="user")
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository") 
 * @UniqueEntity(fields={"email"}, message="There is already an account with this email")
 */
class User implements UserInterface, \Serializable 
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;
    /**
     * @var string
     *
     * @ORM\Column(name="email", type="string", length=2048, nullable=true)
     */
    private $email;
    /**
     * @var string
     *
     * @ORM\Column(name="password", type="string", length=4096, nullable=false)
     */
    private $password;
    /**
     * @var string
     *
     * @ORM\Column(name="salt", type="string", length=2048, nullable=true)
     */
    private $salt;
    ////////
    public function getId(): ?int
    {
        return $this->id;
    }
    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;
        return $this;
    }
    public function getPassword(): ?string
    {
        return $this->password;
    }
    public function setPassword(string $password): self
    {
        $this->password = $password;
        return $this;
    }
    public function getSalt(): ?string
    {
        return $this->salt;
    }
    public function setSalt(string $salt): self
    {
        $this->salt = $salt;
        return $this;
    }

    /**
     * @inheritDoc
     */
    public function getUsername()
    {
        return $this->email;
    }
    /**
     * @inheritDoc
     */
    public function getRoles()
    {
        return array('ROLE_USER');
    }
    /**
     * @inheritDoc
     */
    public function eraseCredentials()
    {
    }
    /**
     * @inheritDoc
     */
    public function equals(UserInterface $user)
    {
        return $this->id === $user->getId();
    }
    /**
     * @see \Serializable::serialize()
     */
    public function serialize()
    {
        return serialize(array(
            $this->id,
        ));
    }
    /**
     * @see \Serializable::unserialize()
     */
    public function unserialize($serialized)
    {
        list (
            $this->id,
        ) = unserialize($serialized);
    }
    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof User) {
            return false;
        }
        if ($this->password !== $user->getPassword()) {
            return false;
        }
        if ($this->salt !== $user->getSalt()) {
            return false;
        }
        if ($this->email !== $user->getEmail()) {
            return false;
        }
        return true;
    }
}

Edit.. When the exception is commented in, the logs say:编辑.. 注释异常时,日志显示:

INFO
19:32:37
request Matched route "app_login".
Show context
INFO
19:32:38
security    Guard authentication successful!
Show context
CRITICAL
19:32:38
request Uncaught PHP Exception Exception: "TODO: provide a valid redirect inside /var/www/src/Security/LoginFormAuthenticator.php" at /var/www/src/Security/LoginFormAuthenticator.php line 87

And when the redirect is there the logs say:当重定向在那里时,日志说:

19:30:24
security    Checking for guard authentication credentials.
Hide context
[▼
  "firewall_key" => "main"
  "authenticators" => 1
]
19:30:24
security    Checking support on guard authenticator.
Hide context
[▼
  "firewall_key" => "main"
  "authenticator" => "App\Security\LoginFormAuthenticator"
]
19:30:24
security    Guard authenticator does not support the request.
Hide context
[▼
  "firewall_key" => "main"
  "authenticator" => "App\Security\LoginFormAuthenticator"
]

..edit - and same behaviour in both http & https. ..edit - 和 http 和 https 中的相同行为。

I wanted to leave a comment for you, but my reputation is less than 50 so I'll write my comment in the answer.我想为你留下评论,但我的声誉不到50,所以我会在答案中写下我的评论。

The support method is deprecated.不推荐使用支持方法。 Don't use it anymore.不要再使用它了。

Use the following example:使用以下示例:

LoginFormAuthenticator.php LoginFormAuthenticator.php

public function getCredentials(Request $request)
{
    $isLoginSubmit = 'user_login' === $request->attributes->get('_route') && $request->isMethod('POST');
    if(!$isLoginSubmit) {
        return;
    }

    //...other codes
}
protected function getDefaultSuccessRedirectUrl()
{
    return $this->urlGenerator->generate('user_dashboard');
}

UserController.php用户控制器.php

<?php

namespace AppBundle\Controller\User;

use AppBundle\Form\User\UserManager\UserLoginForm;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;

/**
 * User controller.
 *
 * @Route("User")
 */
class UserController extends Controller
{

    /**
     * @Route("/login", name="user_login")
     */
    public function loginAction()
    {
        $authenticationUtils = $this->get('security.authentication_utils');
        // get the login error if there is one
        $error = $authenticationUtils->getLastAuthenticationError();
        // last username entered by the user
        $lastUsername = $authenticationUtils->getLastUsername();

        $form = $this->createForm(UserLoginForm::class, ["_username" => $lastUsername]);

        return $this->render('User/login.html.twig', [
            'form'  => $form->createView(),
            'error' => $error,
        ]);
    }

    /**
     * @Route("/logout", name="user_logout")
     */
    public function logoutAction()
    {
        throw new \Exception('User logout');
    }

    /**
     * @Route("/dashboard", name="user_dashboard")
     */
    public function dashboardAction()
    {
        return $this->render('User/dashboard.html.twig');
    }
}

security.yaml安全.yaml

Provider and pattern is required:需要提供程序和模式:

firewalls:
    //...other firewalls
    main:
        anonymous: ~
        pattern: ^/user
        provider: users

access_control:
    - { path: ^/user/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/user, roles: ROLE_USER }

Hope to help you.希望能帮到你。

Leave a comment with any feedback.留下任何反馈意见。

The problem was that the user wasn't being refreshed, the Guard Authenticator was doing exactly what it should.问题是用户没有被刷新,Guard Authenticator 正在做它应该做的事情。 Stripping back the User Entity to the following fixed it.将用户实体剥离到以下修复它。

<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 * @UniqueEntity(fields={"email"}, message="There is already an account with this email")
 */
class User implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255, unique=true)
     */
    private $email;
    /**
     * @ORM\Column(type="string", length=255)
     */
    private $password;
    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;
    public function getId(): ?int
    {
        return $this->id;
    }
    public function getEmail(): ?string
    {
        return $this->email;
    }
    public function setEmail(string $email): self
    {
        $this->email = $email;
        return $this;
    }
    public function getUsername()
    {
        return $this->email;
    }
    public function getPassword(): ?string
    {
        return $this->password;
    }
    public function setPassword(string $password): self
    {
        $this->password = $password;
        return $this;
    }
    public function getName(): ?string
    {
        return $this->name;
    }
    public function setName(string $name): self
    {
        $this->name = $name;
        return $this;
    }
    ////
    public function getRoles()
    {
        return [
            'ROLE_USER'
        ];
    }
    public function getSalt()
    {  
    }
    public function eraseCredentials()
    {
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM