#php #frameworks #symfony5
Вопрос:
Мой вопрос более абстрактен, чем задан.
У нас есть две таблицы «Пользователи» и «Роли», и одна из них представляет собой связь между двумя предыдущими. Мой вопрос в том, какова должна быть правильная взаимосвязь между двумя таблицами, чтобы иметь возможность использовать логин и регистрацию из документации Symfony. Я думаю, что мне чего-то не хватает во всей этой концепции. Источник: https://symfony.com/doc/current/security/form_login_setup.html
Заранее спасибо!
РЕДАКТИРОВАТЬ: Я создал таблицы и отношения с помощью терминала доктрины
Сущность пользователя:
<?php
namespace AppEntity;
use AppRepositoryUserRepository;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineORMMapping as ORM;
use SymfonyBridgeDoctrineValidatorConstraintsUniqueEntity;
use SymfonyComponentSecurityCoreUserUserInterface;
/**
* @ORMEntity(repositoryClass=UserRepository::class)
* @UniqueEntity(fields={"email"}, message="There is already an account with this email")
*/
class User implements UserInterface
{
public function __construct()
{
$this->date_created = new DateTime();
$this->roles = new ArrayCollection();
}
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
private $id;
/**
* @ORMColumn(type="string", length=150, nullable=true)
*/
private $first_name;
/**
* @ORMColumn(type="string", length=150, nullable=true)
*/
private $last_name;
/**
* @ORMColumn(type="string", length=255)
*/
private $email;
/**
* @ORMColumn(type="string", length=255)
*/
private $password;
/**
* @ORMColumn(type="string", length=100)
*/
private $username;
/**
* @ORMColumn(type="boolean")
*/
private $active = 0;
/**
* @ORMColumn(type="datetime")
*/
private $date_created;
/**
* @ORMColumn(type="boolean")
*/
private $isVerified = false;
/**
* @var Collection|Roles[]
* @ORMManyToMany(targetEntity="Roles")
* @ORMJoinTable(
* name="user_roles",
* joinColumns={@ORMJoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORMJoinColumn(name="role_id", referencedColumnName="id")}
* )
*/
private $roles;
public function getId(): ?int
{
return $this->id;
}
public function getFirstName(): ?string
{
return $this->first_name;
}
public function setFirstName(?string $first_name): self
{
$this->first_name = $first_name;
return $this;
}
public function getLastName(): ?string
{
return $this->last_name;
}
public function setLastName(?string $last_name): self
{
$this->last_name = $last_name;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function getUsername(): ?string
{
return $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
public function getActive(): ?bool
{
return $this->active;
}
public function setActive(bool $active): self
{
$this->active = $active;
return $this;
}
public function getDateCreated(): ?DateTimeInterface
{
return $this->date_created;
}
public function setDateCreated(DateTimeInterface $date_created): self
{
$this->date_created = $date_created;
return $this;
}
/**
* @param Collection $roles
*/
public function setRoles(Collection $roles): void
{
$this->roles = $roles;
}
/**
* @return Collection
*/
public function getRoles(): Collection
{
return $this->roles;
}
/**
* @param mixed $password
*/
public function setPassword($password): void
{
$this->password = $password;
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
return null;
}
public function eraseCredentials()
{
// TODO: Implement eraseCredentials() method.
}
public function isVerified(): bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): self
{
$this->isVerified = $isVerified;
return $this;
}
public function addRole(Roles $role)
{
if ($this->roles->contains($role)) {
return;
}
$this->roles->add($role);
}
public function removeRole(Roles $role)
{
if (!$this->roles->contains($role)) {
return;
}
$this->roles->removeElement($role);
}
}
Сущность ролей:
<?php
namespace AppEntity;
use AppRepositoryRolesRepository;
use DoctrineORMMapping as ORM;
/**
* @ORMEntity(repositoryClass=RolesRepository::class)
*/
class Roles
{
/**
* @ORMId
* @ORMGeneratedValue
* @ORMColumn(type="integer")
*/
private $id;
/**
* @ORMColumn(type="string", length=30)
*/
private $system_name;
/**
* @ORMColumn(type="string", length=30)
*/
private $name;
public function getId(): ?int
{
return $this->id;
}
public function getSystemName(): ?string
{
return $this->system_name;
}
public function setSystemName(string $system_name): self
{
$this->system_name = $system_name;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}
Here is my LoginFormAuthenticator from Symfony documentantion:
<?php
namespace AppSecurity;
use AppEntityUser;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentHttpFoundationRedirectResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentRoutingGeneratorUrlGeneratorInterface;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityCoreExceptionCustomUserMessageAuthenticationException;
use SymfonyComponentSecurityCoreExceptionInvalidCsrfTokenException;
use SymfonyComponentSecurityCoreSecurity;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityCsrfCsrfToken;
use SymfonyComponentSecurityCsrfCsrfTokenManagerInterface;
use SymfonyComponentSecurityGuardAuthenticatorAbstractFormLoginAuthenticator;
use SymfonyComponentSecurityHttpUtilTargetPathTrait;
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
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 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();
}
/** @var User $user */
$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, string $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('index'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
Я вручную создаю одного пользователя в базе данных, устанавливаю связи с таблицей ролей, и после попытки входа в систему с этим пользователем возникает ошибка, подобная этой
Аргумент 3, переданный SymfonyComponentSecurityGuardTokenPostAuthenticationGuardToken::__construct() должен иметь тип массива, заданный объект, вызываемый в /var/www/fitter/vendor/symfony/security-guard/AbstractGuardAuthenticator.php на линии 35
По-старому с такими ролями, как [«ROLE_USER», «ROLE_ADMIN»] в приложении «Таблица пользователей», работало, но моя цель-использовать связанные роли.
Я не могу понять, как передать правильный тип ролей, чтобы аутентификатор входа работал с этим потоком.
Комментарии:
1. Абстрактный или нет, ваш вопрос довольно расплывчат. На самом деле вы не представили проблему; что означает «Я думаю, что мне чего-то не хватает во всей концепции»? Вы создаете сущности после создания таблиц (обычно это делается наоборот)? Что заставляет вас думать, что ваши столы не подойдут? С какой частью этой системы у вас возникли проблемы?
2. Я отредактировал сообщение, извините за пропущенную информацию.