symfony 5 проблема аутентификации с getUser () - PullRequest
0 голосов
/ 27 февраля 2020

Я пытаюсь работать с Symfony 5 и компонентом безопасности, и я заблокирован из-за ошибки. ошибка при успешной аутентификации после перенаправления, $this->getUser() возвращает ноль, но в то же время панель разработки показывает мою роль (которая хранится в базе данных)

my security.yaml:


security:
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        in_database:
            entity:
                class: App\Entity\User
                property: email

    role_hierarchy:
        ROLE_CLIENT:      ROLE_USER
        ROLE_ADMIN:       ROLE_CLIENT
        ROLE_DEV: [ROLE_CLIENT, ROLE_ADMIN]

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            provider: in_database
            form_login:
                check_path: app_login
                login_path: app_login
                default_target_path:  /test
                username_parameter: email
                password_parameter: password
                csrf_parameter: _csrf_security_token
                csrf_token_id: a_private_string
            logout:
                path: app_logout
                target: app_login


            # 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: ^/backoffice, roles: ROLE_ADMIN }
        - { path: ^/profile, roles: ROLE_USER }
    encoders:
        App\Entity\User: plaintext

И я не изменил сущность пользователя.

edit

Следуя советам, я добавил эти строки в свой security.yaml :

guard:
    authenticators:
        - App\Security\LoginFormAuthentificator

И файл LoginFormAuthentificator (извините, это будет долго)

<?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\RouterInterface;
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\Http\Util\TargetPathTrait;

class LoginFormAuthentificator extends AbstractFormLoginAuthenticator {
    use TargetPathTrait;

    private $entityManager;
    private $router;
    private $csrfTokenManager;
    private $passwordEncoder;

    public function __construct(EntityManagerInterface $entityManager, RouterInterface $router, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder){
        $this->entityManager = $entityManager;
        $this->router = $router;
        $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 = ['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){
        return $this->passwordEncoder->isPasswordValid($user, $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->router->generate('BackOffice_home_index'));
        // throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
    }

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

Большое спасибо за помощь и время.

1 Ответ

1 голос
/ 27 февраля 2020

После некоторой отладки я обнаружил, что вы реализуете Serializable интерфейс для вашего User класса. При таком подходе методы из этого интерфейса должны возвращать правильные данные, потому что эти методы будут сериализованы для объекта User в сеансе. В вашем случае методы, serialize и unserialize были пустыми, что привело к сохранению нулевого значения в сеансе. Поэтому вы должны удалить интерфейс Serializable и его методы из вашего класса User (в этом случае приложение хранит некоторые поля по умолчанию в сеансе) или реализовать по крайней мере минимальную функциональность для этих методов:

public function serialize(){
    return serialize([
        $this->id,
        $this->email,
        $this->password
    ]); 
}

public function unserialize($serialized){
    list(
        $this->id, 
        $this->email, 
        $this->password
    ) = unserialize($serialized, ['allowed_classes' => false]);
}

также добавьте возвращаемое значение в метод getUsername, реализованный из UserInterface, например

public function getUsername(){
    return $this->email;
}

Дополнительная информация здесь и здесь

...