Symfony security использует неправильный псевдоним таблицы sql во время аутентификации

#php #symfony #authentication #sulu

#php #symfony #аутентификация #sulu

Вопрос:

Я пытаюсь создать свою собственную пользовательскую сущность, которая расширяет сущность SuluUser (чтобы я мог добавить некоторые свойства). После выполнения инструкций из документации Sulu: Extend Entities я затем создал свою собственную аутентификацию symfony для (переднего) веб-сайта, однако при попытке аутентификации я получаю следующую ошибку.

Редактировать: добавлены импорт и аннотации для объекта user

При выполнении ‘ВЫБЕРИТЕ t1.username КАК username_2, t1.password КАК password_3, t1.locale КАК locale_4, t1.salt КАК salt_5, t1.locked КАК locked_6, t1.enabled КАК enabled_7, t1.lastLogin КАК lastLogin_8, t1.confirmationKey КАК confirmationKey_9, t1.passwordResetToken КАК passwordResetToken_10, t1.passwordResetTokenExpiresAt КАК passwordResetTokenExpiresAt_11, t1.passwordResetTokenEmailsSent КАК passwordResetTokenEmailsSent_12, t1.PrivateKey КАК privateKey_13, t1.apiKey КАК apiKey_14, t1.email КАК email_15, t1.id КАК id_16, t1.firstname КАК firstname_17, t1.lastname КАК lastname_18, t1.phonenumber КАК phonenumber_19, t1.gender КАК gender_20, t1.password_changed_date КАК password_changed_date_21, t1.confirmation_token КАК confirmation_token_22, t1.idContacts КАК idContacts_23 ОТ пользователя t1, ГДЕ t0.email = ? ОГРАНИЧЕНИЕ 1’ с помощью параметров [«test@test.com «]:

SQLSTATE[42S22]: столбец не найден: 1054 неизвестных столбца ‘t0.email’ в ‘where предложение’

Я не уверен, почему он использует t0.email, когда остальная часть запроса использует t1 в качестве псевдонима, но это прерывает вход с (переднего) веб-сайта. Администратор может войти в систему просто отлично для серверной части sulu. Я полагаю, что это как-то связано с наследованием с SuluUser, которое расширяет моя пользовательская сущность. Любая помощь была бы очень признательна. Я читал здесь о наследовании doctrine, но я не думаю, что это относится ко мне, поскольку я не могу (не должен) изменять класс в Sulu Bundle SecurityBundle Entity User . Я настроил следующее

Приложение Сущность Пользователь

 namespace AppEntity;

use DoctrineORMMapping as ORM;
use SymfonyBridgeDoctrineValidatorConstraintsUniqueEntity;
use SuluBundleSecurityBundleEntityUser as SuluUser;
use SymfonyComponentSecurityCoreValidatorConstraintsUserPassword;
use SymfonyComponentSerializerAnnotationGroups;
use SymfonyComponentValidatorConstraints as Assert;
/**
 * @ORMEntity(repositoryClass="AppRepositoryUserRepository")
 * @UniqueEntity(fields={"email"})
 */
class User extends SuluUser
{

    /**

     * @Groups({"get", "post", "put", "get-comment-with-author", "get-blog-post-with-author"})
     * @ORMColumn(type="string", length=25)
     * @AssertNotBlank(groups={"post"})
     * @AssertLength(min=4, max="100")
     */
    private $Firstname;

    /**
     * @Groups({"get", "post", "put"})
     * @ORMColumn(type="string", length=25)
     * @AssertNotBlank(groups={"post"})
     * @AssertLength(min=4, max="100")
     */
    private $Lastname;

    /**
     * @ORMColumn(type="string", length=10, nullable=true)
     *
     * @Groups({"get", "post", "put"})
     */
    private $phonenumber;

    /**
     * @ORMColumn(type="string", nullable=true)
     * @Groups({"get", "post", "put"})
     * @AssertCollection()
     */
    private $gender;


    /**
     * @Groups({"post"})
     * @AssertNotBlank(groups={"post"})
     * @AssertExpression(
     *     "this.getPassword() === this.getRetypedPassword()",
     *     message="Passwords do not match"
     * )
     */
    private $retypedPassword;


    /**
     * @AssertLength(min=10, max="100")
     * @AssertNotBlank(groups={"put-reset-password"})
     * @Groups({"put-reset-password"})
     * @AssertRegex(
     *     pattern="/(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{7,}/",
     *     message="Your password needs to be at least 10 characters long and contain the folloiwing"
     * )
     */
    private $newPassword;


    /**
     * @Groups({"put-reset-password"})
     * @AssertNotBlank(groups={"put-reset-password"})
     * @AssertExpression(
     *     "this.getNewPassword() === this.getNewRetypedPassword()",
     *     message="Passwords does not match",
     *     groups={"put-reset-password"}
     * )
     */
    private $newRetypedPassword;


    /**
     * @Groups({"put-reset-password"})
     * @AssertNotBlank(groups={"put-reset-password"})
     * @UserPassword(groups={"put-reset-password"})
     */
    private $oldPassword;
    /**
     * @ORMColumn(type="integer", nullable=true)
     */
    private $passwordChangedDate;

    /**
     * @ORMColumn(type="string", length=40, nullable=true)
     */
    private $confirmationToken;


    public function __construct()
    {
        $this->confirmationToken = null;

    }


    public function getFirstname(): ?string
    {
        return $this->Firstname;
    }

    public function setFirstname( $Firstname): self
    {
        $this->Firstname = $Firstname;

        return $this;
    }

    public function getLastname(): ?string
    {
        return $this->Lastname;
    }

    public function setLastname( $Lastname): self
    {
        $this->Lastname = $Lastname;

        return $this;
    }

    public function getPhonenumber(): ?string
    {
        return $this->phonenumber;
    }

    public function setPhonenumber(?string $phonenumber): self
    {
        $this->phonenumber = $phonenumber;

        return $this;
    }

    /**
     * @return mixed
     */
    public function getGender()
    {
        return $this->gender;
    }

    /**
     * @param mixed $gender
     */
    public function setGender($gender): void
    {
        $this->gender = $gender;
    }


    /**
     * @return mixed
     */
    public function getRetypedPassword()
    {
        return $this->retypedPassword;
    }

    /**
     * @param mixed $retypedPassword
     */
    public function setRetypedPassword($retypedPassword): void
    {
        $this->retypedPassword = $retypedPassword;
    }

    public function getNewPassword(): ?string
    {
        return $this->newPassword;
    }

    public function setNewPassword($newPassword): void
    {
        $this->newPassword = $newPassword;
    }

    public function getNewRetypedPassword(): ?string
    {
        return $this->newRetypedPassword;
    }

    public function setNewRetypedPassword($newRetypedPassword): void
    {
        $this->newRetypedPassword = $newRetypedPassword;
    }

    public function getOldPassword(): ?string
    {
        return $this->oldPassword;
    }

    public function setOldPassword($oldPassword): void
    {
        $this->oldPassword = $oldPassword;
    }

    public function getPasswordChangedDate()
    {
        return $this->passwordChangedDate;
    }

    public function setPasswordChangedDate($passwordChangedDate): void
    {
        $this->passwordChangedDate = $passwordChangedDate;
    }


    public function getConfirmationToken()
    {
        return $this->confirmationToken;
    }


    public function setConfirmationToken($confirmationToken): void
    {
        $this->confirmationToken = $confirmationToken;
    }



    public function __toString(): string
    {
        return $this->Firstname . ' ' . $this->Lastname;
    }

}
  

App config packgessecurity_website.yaml

 security:
  encoders:
    AppEntityUser:
      algorithm: auto


  providers:
    app_user_provider:
      entity:
        class: AppEntityUser
        property: email
  firewalls:
    dev:
      pattern: ^/(_(profiler|wdt)|css|images|js)/
      security: false
    main:
      anonymous: false
      lazy: true
      provider: app_user_provider
      guard:
        authenticators:
          - AppSecurityAppAuthenticator
      logout:
        path: app_logout
        # where to redirect after logout
        target: home
  

Приложение Безопасность AppAuthenticator

 class AppAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
    use TargetPathTrait;

    public const LOGIN_ROUTE = 'app.login';

    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 self::LOGIN_ROUTE === $request->attributes->get('_route')
            amp;amp; $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']);
    }

    /**
     * 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);
        }

        $role =  $token->getUser()->getRoles();

        // For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
       // throw new Exception('TODO: provide a valid redirect inside '.__FILE__);
      //  return new RedirectResponse('admin');

                return new RedirectResponse('/');


    }

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

Ответ №1:

Очень важно, чтобы при переопределении объектов Sulu вы устанавливали его на то же имя таблицы, иначе переопределение объекта работает некорректно, так как в документации для @ORMTable заданы «se_users» и @ORM Entity.

 <?php

namespace AppEntity;

use DoctrineORMMapping as ORM;
use SuluBundleSecurityBundleEntityUser as SuluUser;

/**
 * Following annotations are required and should not be changed:
 *
 * @ORMTable(name="se_users")
 * @ORMEntity
 */
class User extends SuluUser
{
}
  

Комментарии:

1. Извините, пожалуйста, не обращайте внимания на мой предыдущий комментарий. Кажется, я вернулся к тому, что у меня есть сейчас, во время отладки и оставил его там. Я изменил его так, чтобы он был точно таким, как в приведенном выше ответе, однако теперь я просто получаю сообщение об ошибке doctrine, в котором говорится, что таблица с именем ‘sulu-workshop.se_users’ уже существует

2. Не обращайте внимания еще раз. Большое вам спасибо, что указали на это. Это показало мне ошибку моих путей. Очень признателен, сэр!

3. Каким было решение @TrueSaint ? В настоящее время я борюсь с тем же поведением, но конфигурация и конфигурация таблицы на месте.

4. Хорошо, похоже, что существует комбинация версий пакета, которая выдает ту же ошибку «таблица уже существует», даже если атрибуты установлены. После обновления composer все работает как ожидалось.