I am trying to make my own User entity which extends the SuluUser entity (so I can add some properties). After following the instructions from the Sulu documentation: Extend Entities I then created my own symfony authentication for the (front) website however, when I try to authenticate I get the following error.
Edit: added the imports and annotations for the user entity
An exception occurred while executing 'SELECT t1.username AS username_2, t1.password AS password_3, t1.locale AS locale_4, t1.salt AS salt_5, t1.locked AS locked_6, t1.enabled AS enabled_7, t1.lastLogin AS lastLogin_8, t1.confirmationKey AS confirmationKey_9, t1.passwordResetToken AS passwordResetToken_10, t1.passwordResetTokenExpiresAt AS passwordResetTokenExpiresAt_11, t1.passwordResetTokenEmailsSent AS passwordResetTokenEmailsSent_12, t1.privateKey AS privateKey_13, t1.apiKey AS apiKey_14, t1.email AS email_15, t1.id AS id_16, t1.firstname AS firstname_17, t1.lastname AS lastname_18, t1.phonenumber AS phonenumber_19, t1.gender AS gender_20, t1.password_changed_date AS password_changed_date_21, t1.confirmation_token AS confirmation_token_22, t1.idContacts AS idContacts_23 FROM user t1 WHERE t0.email = ? LIMIT 1' with params ["test#test.com"]:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 't0.email' in 'where clause'
I'm not sure why it's using t0.email when the rest of the query uses t1 as an alias, but this breaks the login from the (front) website. Admin can login just fine for the sulu backend. I believe it has something to do with the inheritance with the SuluUser that my User entity extends. Any help would be very much appreciated. I have read about doctrine inheritance here but I don't think that applies to me as I cannot (should not) change the class in Sulu\Bundle\SecurityBundle\Entity\User. I have configured the following
App\Entity\User
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Sulu\Bundle\SecurityBundle\Entity\User as SuluUser;
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
* #UniqueEntity(fields={"email"})
*/
class User extends SuluUser
{
/**
* #Groups({"get", "post", "put", "get-comment-with-author", "get-blog-post-with-author"})
* #ORM\Column(type="string", length=25)
* #Assert\NotBlank(groups={"post"})
* #Assert\Length(min=4, max="100")
*/
private $Firstname;
/**
* #Groups({"get", "post", "put"})
* #ORM\Column(type="string", length=25)
* #Assert\NotBlank(groups={"post"})
* #Assert\Length(min=4, max="100")
*/
private $Lastname;
/**
* #ORM\Column(type="string", length=10, nullable=true)
*
* #Groups({"get", "post", "put"})
*/
private $phonenumber;
/**
* #ORM\Column(type="string", nullable=true)
* #Groups({"get", "post", "put"})
* #Assert\Collection()
*/
private $gender;
/**
* #Groups({"post"})
* #Assert\NotBlank(groups={"post"})
* #Assert\Expression(
* "this.getPassword() === this.getRetypedPassword()",
* message="Passwords do not match"
* )
*/
private $retypedPassword;
/**
* #Assert\Length(min=10, max="100")
* #Assert\NotBlank(groups={"put-reset-password"})
* #Groups({"put-reset-password"})
* #Assert\Regex(
* 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"})
* #Assert\NotBlank(groups={"put-reset-password"})
* #Assert\Expression(
* "this.getNewPassword() === this.getNewRetypedPassword()",
* message="Passwords does not match",
* groups={"put-reset-password"}
* )
*/
private $newRetypedPassword;
/**
* #Groups({"put-reset-password"})
* #Assert\NotBlank(groups={"put-reset-password"})
* #UserPassword(groups={"put-reset-password"})
*/
private $oldPassword;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $passwordChangedDate;
/**
* #ORM\Column(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\packges\security_website.yaml
security:
encoders:
App\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: false
lazy: true
provider: app_user_provider
guard:
authenticators:
- App\Security\AppAuthenticator
logout:
path: app_logout
# where to redirect after logout
target: home
App\Security\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')
&& $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);
}
}
Its very important when you override the Sulu entities that you set it on the same table name else the override of the entity does not work correctly so as in the documentation set the #ORM\Table with "se_users" and #ORM\Entity to it.
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sulu\Bundle\SecurityBundle\Entity\User as SuluUser;
/**
* Following annotations are required and should not be changed:
*
* #ORM\Table(name="se_users")
* #ORM\Entity
*/
class User extends SuluUser
{
}
Related
I have a colleague entity, which has a many to one relation with user entity.
I want to only have the ability to access colleagues attached to identified user.
This is for all CRUD permissions: list, edit, update, delete.
I've tried a lot of things, like DQL filter in easy_admin.yaml, but I can't manage to get authenticated user id.
I'm a Symfony junior, so I don't know how to do this and I must use Easyadmin.
So, it seems I can't use ColleagueController.php. Maybe with ColleagueRepository.php?
For the moment, everything is configured in easy_admin.yaml:
easy_admin:
design:
templates:
label_null: 'null_value.html.twig'
entities:
Colleague:
class: App\Entity\Colleague
list:
# dql_filter: "entity.user = 15"
# dql_filter: "entity.user = '%env(AUTHENTICATED_USER)%'"
# dql_filter: "entity.user = (SELECT id FROM user WHERE email = '%env(AUTHENTICATED_USER)%')"
# dql_filter: "entity.user = (SELECT id FROM App\Entity\User WHERE email = 'aaa#gmail.com')"
fields:
- user
- name
- role
- notes
- { property: 'thumbnail', type: 'image', base_path: '%uploads_path%' }
actions: ['show', 'edit', 'delete']
form:
fields:
- user
- name
- role
- notes
- { property: 'thumbnailFile', type: 'vich_image' }
show:
fields:
- user
- name
- role
- notes
- { property: 'thumbnail', type: 'image', base_path: '%uploads_path%' }
And my Entity\Colleague.php:
<?php
namespace App\Entity;
use App\Repository\ColleagueRepository;
use Doctrine\ORM\Mapping as ORM;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\HttpFoundation\File\File;
/**
* #ORM\Entity(repositoryClass=ColleagueRepository::class)
* #Vich\Uploadable
*/
class Colleague
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="colleagues")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $role;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $notes;
/**
* #ORM\Column(type="string", length=255, nullable=true, options={"default": 0})
*
* #var string
*/
private $thumbnail;
/**
* #Vich\UploadableField(mapping="colleague_thumbnails", fileNameProperty="thumbnail")
*
* #var File
*/
private $thumbnailFile;
/**
* #ORM\Column(type="datetime")
*
* #var \DateTime
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
*
* #var \DateTime
*/
private $updatedAt;
public function __construct()
{
$this->setCreatedAt(new \DateTime());
$this->setUpdatedAt(new \DateTime());
// var_dump($this->get('security.token_storage')->getToken()->getUser());
// die;
}
public function getId(): ?int
{
return $this->id;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getRole(): ?string
{
return $this->role;
}
public function setRole(?string $role): self
{
$this->role = $role;
return $this;
}
public function getNotes(): ?string
{
return $this->notes;
}
public function setNotes(?string $notes): self
{
$this->notes = $notes;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
public function getThumbnail(): ?string
{
return $this->thumbnail;
}
public function setThumbnail(?string $thumbnail): self
{
$this->thumbnail = $thumbnail;
return $this;
}
/**
* #return File
*/
public function getThumbnailFile()
{
return $this->thumbnailFile;
}
/**
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $image
*
* #return User
*/
public function setThumbnailFile(File $thumbnail = null)
{
$this->thumbnailFile = $thumbnail;
if ($thumbnail) {
$this->updatedAt = new \DateTime('now');
}
return $this;
}
}
Thanks in advance for your precious help.
Here is the same answer as proposed on Linkedin: easy admin advanced permissions. (french post content)
You can combine an event subscriber with a voter, simply follow this example.
Best regards.
I've managed to do Easyadmin specific filtering this way:
config/packages/easy_admin.yaml:
easy_admin:
entities:
Colleague:
class: App\Entity\Colleague
controller: App\Controller\ColleagueController
src/Controller/ColleagueController.php:
<?php
namespace App\Controller;
use Symfony\Component\Routing\Annotation\Route;
use EasyCorp\Bundle\EasyAdminBundle\Controller\EasyAdminController;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class ColleagueController extends EasyAdminController
{
protected function createListQueryBuilder($entityClass, $sortDirection, $sortField = null, $dqlFilter = null)
{
$result = parent::createListQueryBuilder($entityClass, $sortDirection, $sortField, $dqlFilter);
if (method_exists($entityClass, 'getUser')) {
$result->andWhere('entity.user = :user');
$result->setParameter('user', $this->getUser());
}
return $result;
}
protected function createSearchQueryBuilder($entityClass, $searchQuery, array $searchableFields, $sortField = null, $sortDirection = null, $dqlFilter = null)
{
$result = parent::createSearchQueryBuilder($entityClass, $searchQuery, $searchableFields, $sortField, $sortDirection, $dqlFilter);
if (method_exists($entityClass, 'getUser')) {
$result->andWhere('entity.user = :user');
$result->setParameter('user', $this->getUser());
}
return $result;
}
protected function createEditForm($entity, array $entityProperties)
{
$result = parent::createEditForm($entity, $entityProperties);
if ($entity->getUser() !== $this->getUser()) {
throw new AccessDeniedException();
}
return $result;
}
protected function showAction()
{
$easyadmin = $this->request->attributes->get('easyadmin');
$entity = $easyadmin['item'];
if ($entity->getUser() !== $this->getUser()) {
throw new AccessDeniedException();
}
$result = parent::showAction();
return $result;
}
protected function deleteAction()
{
$easyadmin = $this->request->attributes->get('easyadmin');
$entity = $easyadmin['item'];
if ($entity->getUser() !== $this->getUser()) {
throw new AccessDeniedException();
}
$result = parent::deleteAction();
return $result;
}
/**
* Create a colleague.
*/
protected function persistEntity($entity)
{
$entity->setUser($this->getUser());
$result = parent::persistEntity($entity);
return $result;
}
}
I'm using a custom authenticator and a custom user provider in Symfony 5.0.10
Some of my users have complained that they can't login anymore : in fact in some cases, the login will be sucessful (onAuthenticationSuccess is called) but the user will still be anonymous. This causes a direct redirection to login page.
This is solved by clearing the cookies (PHPSESSID) or by using a private navigation window. I can't explain how thats comes into the login logic of an anonymous user.
If you guys can find the issue that would really help me, i've been spending a few all nighters on this and can't figure it out.
Here is my code :
security.yaml
security:
encoders:
App\Security\User:
algorithm: none
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_galette_user_provider:
id: App\Security\GaletteUserProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: lazy
provider: app_galette_user_provider
logout:
path: app_logout
guard:
authenticators:
- App\Security\AppCustomAuthenticator
# where to redirect after logout
# target: app_any_route
# 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: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }
Custom Authenticator (AppCustomAuthenticator.php)
<?php
namespace App\Security;
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\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
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\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class AppCustomAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
public function __construct(UrlGeneratorInterface $urlGenerator, UserPasswordEncoderInterface $passwordEncoder)
{
$this->urlGenerator = $urlGenerator;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return 'app_login' === $request->attributes->get('_route') && $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'username' => $request->request->get('email'),
'password' => $request->request->get('password'),
//'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['username']
);
return $credentials;
}
public function supportsRememberMe()
{
return false;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
// Load / create our user however you need.
// You can do this by calling the user provider, or with custom logic here.
try {
$user = $userProvider->loadUserByUsername($credentials['username']);
} catch (UsernameNotFoundException $e) {
throw new CustomUserMessageAuthenticationException("Erreur lors de la connexion : veuillez vérifier vos identifiants et l'état de votre cotisation.");
}
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('Email could not be found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
if ($credentials['password'] === $user->getPassword()) {
return true;
}
return false;
}
/**
* 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)
{
return new RedirectResponse($this->urlGenerator->generate('index'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate("app_login");
}
}
And my User.php entity :
<?php
namespace App\Security;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface, EquatableInterface
{
private $id;
private $email;
private $roles;
private $password;
private $nom;
private $prenom;
private $adresse;
private $adresse2;
private $cp;
private $ville;
private $pays;
private $tel;
private $gsm;
private $salt;
private $username;
public function isEqualTo(UserInterface $user)
{
if ($this->getUsername() !== $user->getUsername()) {
return false;
}
return true;
}
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #param int $id
*/
public function setId($id): void
{
$this->id = $id;
}
/**
* #return string
*/
public function getNom(): string
{
return $this->nom;
}
/**
* #param string $nom
*/
public function setNom($nom): void
{
$this->nom = $nom;
}
/**
* #return string
*/
public function getPrenom(): string
{
return $this->prenom;
}
/**
* #param string $prenom
*/
public function setPrenom($prenom): void
{
$this->prenom = $prenom;
}
/**
* #return string
*/
public function getAdresse(): string
{
return $this->adresse;
}
/**
* #param string $adresse
*/
public function setAdresse($adresse): void
{
$this->adresse = $adresse;
}
/**
* #return string
*/
public function getAdresse2(): ?string
{
return $this->adresse2;
}
/**
* #param string $adresse2
*/
public function setAdresse2($adresse2): void
{
$this->adresse2 = $adresse2;
}
/**
* #return string
*/
public function getCp(): ?string
{
return $this->cp;
}
/**
* #param string $cp
*/
public function setCp($cp): void
{
$this->cp = $cp;
}
/**
* #return string
*/
public function getVille(): ?string
{
return $this->ville;
}
/**
* #param string $ville
*/
public function setVille($ville): void
{
$this->ville = $ville;
}
/**
* #return string
*/
public function getPays(): ?string
{
return $this->pays;
}
/**
* #param string $pays
*/
public function setPays($pays): void
{
$this->pays = $pays;
}
/**
* #return string
*/
public function getTel(): ?string
{
return $this->tel;
}
/**
* #param string $tel
*/
public function setTel($tel): void
{
$this->tel = $tel;
}
/**
* #return string
*/
public function getGsm(): ?string
{
return $this->gsm;
}
/**
* #param string $gsm
*/
public function setGsm($gsm): void
{
$this->gsm = $gsm;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
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);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function getSalt()
{
return;
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
}
'''
-> I'm not including my custom user provider as i know it to work (it correctly returns the user)
-> My user passwords are indeed "in clear", this is a very specific scenario which poses no security threat
This may be caused by symfony session fixation protection.
It is enabled by default and should refresh session id after user authentication. More info in symfony docs
Check if the PHPSESSID cookie refreshes after EVERY request.
If it does, then your authenticator triggers this method refreshing session id on each user request.
Which leads to the following: if the user makes second request before they receive the response from the previous, their session id becomes invalid, and they become unauthenticated.
You can of course disable this protection in your security config:
security:
session_fixation_strategy: none
but better is to fix the problem and do not create a vulnerability in your system.
I'm trying to test the signup method, however im getting this on the logs.
[2018-08-30 00:13:50] request.INFO: Matched route "signup".
{"route":"signup","route_parameters":{"_route":"signup","_controller":"App\Controller\UserController::signup"},"request_uri":"http://localhost/signup","method":"POST"}
[] [2018-08-30 00:13:50] security.INFO: Populated the TokenStorage
with an anonymous Token. [] [] [2018-08-30 00:13:50] doctrine.DEBUG:
"START TRANSACTION" [] [] [2018-08-30 00:13:50] doctrine.DEBUG:
"ROLLBACK" [] [] [2018-08-30 00:13:50] request.CRITICAL: Uncaught PHP
Exception Doctrine\DBAL\Exception\TableNotFoundException: "An
exception occurred while executing 'INSERT INTO user (email, username,
is_active, password, roles) VALUES (?, ?, ?, ?, ?)': SQLSTATE[HY000]:
General error: 1 no such table: user" at
/Applications/MAMP/htdocs/my_project/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php
line 63 {"exception":"[object]
(Doctrine\DBAL\Exception\TableNotFoundException(code: 0): An
exception occurred while executing 'INSERT INTO user (email, username,
is_active, password, roles) VALUES (?, ?, ?, ?,
?)':\n\nSQLSTATE[HY000]: General error: 1 no such table: user at
/Applications/MAMP/htdocs/my_project/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php:63,
Doctrine\DBAL\Driver\PDOException(code: HY000): SQLSTATE[HY000]:
General error: 1 no such table: user at
/Applications/MAMP/htdocs/my_project/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:82,
PDOException(code: HY000): SQLSTATE[HY000]: General error: 1 no such
table: user at
/Applications/MAMP/htdocs/my_project/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:80)"}
[]
and this as an error
Failed asserting that 500 is identical to 200.
SignUpControllerTest.php
<?php
namespace App\Tests\Controller;
use App\Entity\Product;
use App\Entity\Category;
use App\Entity\User;
use App\Repository\UserRepository;
use App\Repository\CategoryRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\ORM\Tools\SchemaTool;
class SignUpControllerTest extends WebTestCase
{
/**
* #var \Doctrine\ORM\EntityManager
*/
private $em;
/**
* {#inheritDoc}
*/
protected function setUp()
{
self::bootKernel();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager();
parent::setUp();
}
public function testUserCreate()
{
$client = static::createClient();
$client->request('POST', '/signup', [], [], [], json_encode([
'user' => [
'username' => 'chuck_norris',
'password' => 'foobar',
'email' => 'chuck#norris.com',
'roles' => 'ROLE_USER'
],
]));
$response = $client->getResponse();
$this->assertSame(Response::HTTP_OK, $response->getStatusCode());
$data = json_decode($response->getContent(), true);
$this->assertArrayHasKey('user', $data);
$this->assertSame('chuck#norris.com', $data['user']['email']);
$this->assertSame('chuck_norris', $data['user']['username']);
}
UserController.php
/**
* #Route("/signup", name="signup")
*/
public function signup(Request $request, UserPasswordEncoderInterface $passwordEncoder )
{
$user = new User();
$entityManager = $this->getDoctrine()->getManager();
$user->setEmail($request->get('email'));
$user->setPlainPassword($request->get('password'));
$user->setUsername($request->get('username'));
$password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('login');
}
User.php (entity)
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\Entity
* #UniqueEntity(fields="email", message="Email already taken")
* #UniqueEntity(fields="username", message="Username already taken")
*/
class User implements UserInterface, \Serializable
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=190, unique=true)
* #Assert\NotBlank()
* #Assert\Email()
*/
private $email;
/**
* #ORM\Column(type="string", length=190, unique=true)
* #Assert\NotBlank()
*/
private $username;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
/**
* #Assert\NotBlank()
* #Assert\Length(max=190)
*/
private $plainPassword;
/**
* The below length depends on the "algorithm" you use for encoding
* the password, but this works well with bcrypt.
*
* #ORM\Column(type="string", length=64)
*/
private $password;
/**
* #ORM\Column(type="array")
*/
private $roles;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="user")
*/
private $products;
public function __construct()
{
$this->roles = array('ROLE_USER');
$this->isActive = true;
$this->products = new ArrayCollection();
}
// other properties and methods
public function getEmail()
{
return $this->email;
}
public function isEnabled()
{
return $this->isActive;
}
public function setEmail($email)
{
$this->email = $email;
}
public function getUsername()
{
return $this->username;
}
public function setUsername($username)
{
$this->username = $username;
}
public function getPlainPassword()
{
return $this->plainPassword;
}
public function setPlainPassword($password)
{
$this->plainPassword = $password;
}
public function getPassword()
{
return $this->password;
}
public function setPassword($password)
{
$this->password = $password;
}
public function getSalt()
{
// The bcrypt and argon2i algorithms don't require a separate salt.
// You *may* need a real salt if you choose a different encoder.
return null;
}
public function getRoles()
{
return $this->roles;
}
public function eraseCredentials()
{
}
/** #see \Serializable::serialize() */
public function serialize()
{
return serialize(array(
$this->id,
$this->username,
$this->password,
// see section on salt below
// $this->salt,
));
}
/** #see \Serializable::unserialize() */
public function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
// see section on salt below
// $this->salt
) = unserialize($serialized, array('allowed_classes' => false));
}
/**
* #return Collection|Product[]
*/
public function getProducts(): Collection
{
return $this->products;
}
public function addProduct(Product $product): self
{
if (!$this->products->contains($product)) {
$this->products[] = $product;
$product->setUser($this);
}
return $this;
}
public function removeProduct(Product $product): self
{
if ($this->products->contains($product)) {
$this->products->removeElement($product);
// set the owning side to null (unless already changed)
if ($product->getUser() === $this) {
$product->setUser(null);
}
}
return $this;
}
}
I'm trying to build a login/register controller for users but i get Underfined class constant 'ROLE_DEFAULT' when I register new user.
In my UserController, I have this function to register new user:
//src/Controller/UserController
public function registerAction(Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
// 1) build the form
$user = new User();
$form = $this->createForm(UserType::class, $user);
// 2) handle the submit (will only happen on POST)
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// 3) Encode the password (you could also do this via Doctrine listener)
$password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
$apiKey = $passwordEncoder->encodePassword($user, rand(1,9999));
$user->setApiKey($apiKey);
$user->setEnabled(1);
// $user->setSuperadmin(true);
$user->addRole("ROLE_DEFAULT");
// 4) save the User!
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
dump($user);
exit;
}
return $this->render(
'user/register.html.twig',
array('form' => $form->createView())
);
}
The error appear when "$user->addRole("ROLE_DEFAULT");" and this is the screenshot:
//src/Entity/User:
namespace App\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", unique=true)
*/
private $username;
/**
* #ORM\Column(name="lastname", type="string", nullable=true)
*/
protected $lastname;
/**
* #ORM\Column(type="string", unique=true)
*/
private $apiKey;
/**
* #ORM\Column(name="enabled", type="boolean")
*/
protected $enabled;
/**
* #ORM\Column(name="email", type="string", nullable=false)
*/
protected $email;
/**
* #ORM\Column(name="SUPERADMIN", type="boolean", nullable=true)
*/
protected $superadmin;
/**
* The salt to use for hashing
*
* #ORM\Column(name="salt", type="string", nullable=true)
*/
protected $salt;
/**
* Encrypted password. Must be persisted.
*
* #ORM\Column(name="password", type="string", nullable=false)
*/
protected $password;
/**
* Encrypted password. Must be persisted.
*
* #ORM\Column(name="plainPassword", type="string", nullable=false)
*/
protected $plainPassword;
/**
* #var \DateTime
*/
protected $lastLogin;
/**
* Random string sent to the user email address in order to verify it
*
* #var string
*/
protected $confirmationToken;
/**
* #var \DateTime
*/
protected $passwordRequestedAt;
public function __construct()
{
$this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
$this->enabled = false;
// $this->locked = false;
$this->roles = array();
}
public function __toString()
{
return (string) $this->getUsername();
}
public function getId()
{
return $this->id;
}
// USERNAME//
//===========================================================
public function setUsername($username)
{
$this->username = $username;
return $this;
}
public function getUsername()
{
return $this->username;
}
// EMAIL//
//===========================================================
public function getEmail()
{
return $this->email;
}
public function setEmail($email)
{
$this->email = $email;
return $this;
}
// API KEY//
//===========================================================
public function getApiKey()
{
return $this->apiKey;
}
public function setApiKey($apiKey)
{
return $this->apiKey = $apiKey;
}
// PASSWORD//
//===========================================================
/**
* Gets the encrypted password.
*
* #return string
*/
public function getPassword()
{
return $this->password;
}
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Gets the encrypted password.
*
* #return string
*/
public function getPlainPassword()
{
return $this->plainPassword;
}
public function setPlainPassword($password)
{
$this->plainPassword = $password;
}
// SALT//
//===========================================================
public function getSalt()
{
return $this->salt;
}
public function setSalt($salt)
{
return $this->salt = $salt;
}
// LAST LOGIN//
//===========================================================
/**
* Gets the last login time.
*
* #return \DateTime
*/
public function getLastLogin()
{
return $this->lastLogin;
}
public function setLastLogin(\DateTime $time = null)
{
$this->lastLogin = $time;
return $this;
}
// CONFIRMATION TOKEN//
//===========================================================
public function getConfirmationToken()
{
return $this->confirmationToken;
}
public function setConfirmationToken($confirmationToken)
{
$this->confirmationToken = $confirmationToken;
return $this;
}
/**
* Removes sensitive data from the user.
*/
public function eraseCredentials()
{
$this->plainPassword = null;
}
// ROLES//
//===========================================================
// public function getRoles()
// {
// return array('ROLE_USER');
// }
/**
* Returns the user roles
*
* #return array The roles
*/
public function getRoles()
{
$roles = array();
$nameRole = $this->idRole->getNamerole();
$stationCreate = $this->idRole->getStationCreate();
$configurationstationEdit = $this->idRole->getConfigurationstationEdit();
$stationEditor = $this->idRole->getDatastationEdit();
$stationValidate = $this->idRole->getStationValidate();
$newdataCreate = $this->idRole->getNewdataCreate();
$superadmin = $this->superadmin;
if($stationCreate){
$roles = array_merge($roles, array('ROLE_CREATOR'));
}
if($configurationstationEdit){
$roles = array_merge($roles, array('ROLE_CONFIGURATOR'));
}
if($stationEditor){
$roles = array_merge($roles, array('ROLE_EDITOR'));
}
if($stationValidate){
$roles = array_merge($roles, array('ROLE_VALIDATOR'));
}
if($newdataCreate){
$roles = array_merge($roles, array('ROLE_MANAGE'));
}
if($superadmin){
$roles = array_merge($roles, array('ROLE_SUPER_ADMIN'));
}
//echo $nameRole." -- ".$stationCreate." -- ".$configurationstationEdit." -- ".$stationValidate." -- ".$newdataCreate;
//exit;
//dump($this->idRole);
//exit;
// we need to make sure to have at least one role
$roles[] = static::ROLE_DEFAULT;
return array_unique($roles);
}
public function setRoles(array $roles)
{
$this->roles = array();
foreach ($roles as $role) {
$this->addRole($role);
}
return $this;
}
public function removeRole($role)
{
if (false !== $key = array_search(strtoupper($role), $this->roles, true)) {
unset($this->roles[$key]);
$this->roles = array_values($this->roles);
}
return $this;
}
public function hasRole($role)
{
return in_array(strtoupper($role), $this->getRoles(), true);
}
public function addRole($role)
{
$role = strtoupper($role);
if ($role === static::ROLE_DEFAULT) {
return $this;
}
if (!in_array($role, $this->roles, true)) {
$this->roles[] = $role;
}
return $this;
}
// ENABLED//
//===========================================================
public function isEnabled()
{
return $this->enabled;
}
public function setEnabled($boolean)
{
$this->enabled = (Boolean) $boolean;
return $this;
}
// SUPERADMIN//
//===========================================================
public function isSuperAdmin()
{
return $this->hasRole(static::ROLE_SUPER_ADMIN);
}
public function setSuperAdmin($boolean)
{
if (true === $boolean) {
$this->addRole(static::ROLE_SUPER_ADMIN);
} else {
$this->removeRole(static::ROLE_SUPER_ADMIN);
}
return $this;
}
// PASSWORD REQUEST AT//
//===========================================================
/**
* Gets the timestamp that the user requested a password reset.
*
* #return null|\DateTime
*/
public function getPasswordRequestedAt()
{
return $this->passwordRequestedAt;
}
public function isPasswordRequestNonExpired($ttl)
{
return $this->getPasswordRequestedAt() instanceof \DateTime &&
$this->getPasswordRequestedAt()->getTimestamp() + $ttl > time();
}
// EXTRA FUNCTIONS//
//===========================================================
/**
* Serializes the user.
*
* The serialized data have to contain the fields used during check for
* changes and the id.
*
* #return string
*/
public function serialize()
{
return serialize(array(
$this->password,
$this->salt,
$this->username,
$this->enabled,
$this->id,
$this->email,
));
}
/**
* Unserializes the user.
*
* #param string $serialized
*/
public function unserialize($serialized)
{
$data = unserialize($serialized);
// add a few extra elements in the array to ensure that we have enough keys when unserializing
// older data which does not include all properties.
$data = array_merge($data, array_fill(0, 2, null));
list(
$this->password,
$this->salt,
$this->username,
$this->enabled,
$this->id,
$this->email,
) = $data;
}
}
And the security.yml file
//config/packages/security.yml
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
encoders:
App\Entity\User:
algorithm: bcrypt
providers:
in_memory: { memory: ~ }
user:
entity:
class: App\Entity\User
# property: apiKey
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
pattern: ^/
http_basic: ~
provider: user
# activate different ways to authenticate
# http_basic: true
# https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# form_login:
# login_path: security_login
# check_path: security_login
# csrf_token_generator: security.csrf.token_manager
# default_target_path: userRedirectAction
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/user, roles: ROLE_USER }
I want to know what I'm doing wrong or where can i find a good guide to build a login/register system in SYMFONY 4.
Thank you.
The first thing that I noticed is use of static to (presumably) get constant. If that was the intention, it is not right.
See this comment of PHP constatnt official docs to get a grasp of what could go wrong:
PHP Constant - self/static
But, regardless, what I could not see was the constant itself defined within the User class, which I saw belonged to your namespace.
So, in order to use it, please define it like:
class User
{
const ROLE_DEFAULT = "ROLE_DEFAULT";
// ....
// The rest of your code
}
And then use it like:
if ($role === self::ROLE_DEFAULT) {
return $this;
}
Though, I am not sure why would you attempt to add that role in your controller at the first place, however, I leave to you to you to decide.
Hope this helps a bit...
I'm new here and I'm from abroad, so sorry for my mistakes in English. Okey, so I have problem with login system in my first application in Symfony. Before I was writing some simple apps in Laravel. But here, I don't know what's wrong. I made new bundle and my login system stop working. I can put data in form, but when I pass it to authorization, website redirects me to login page and I'm not logged in. This is my code:
Controller:
<?php
// src/AppBundle/Controller/RegistrationController.php
namespace AppBundle\Controller;
use AppBundle\Form\UserType;
use AppBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class RegistrationController extends Controller
{
/**
* #Route("/register", name="user_registration")
*/
public function registerAction(Request $request)
{
// 1) build the form
$user = new User();
$form = $this->createForm(UserType::class, $user);
// 2) handle the submit (will only happen on POST)
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// 3) Encode the password (you could also do this via Doctrine listener)
$password = $this->get('security.password_encoder')
->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
// 4) save the User!
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
// ... do any other work - like sending them an email, etc
// maybe set a "flash" success message for the user
return $this->redirectToRoute('homepage');
}
return $this->render(
'registration/registration.html.twig',
array('form' => $form->createView())
);
}
/**
* #Route("/login", name="user_login")
*/
public function loginAction(Request $request) {
$authenticationUtils = $this->get('security.authentication_utils');
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('registration/login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
/**
* #Route("/login_check", name="user_login_check")
*/
public function loginCheckAction() {
throw new \Exception('This should never be reached!');
}
/**
* #Route("/logout", name="user_logout")
*/
public function logoutAction()
{
throw new \Exception('This should never be reached!');
}
/**
* #Route("/login_failed", name="user_login_fail")
*/
public function loginError() {
return new Response('ERROR');
}
}
security.yml
# To get started with security, check out the documentation:
# http://symfony.com/doc/current/book/security.html
security:
encoders:
# Our user class and the algorithm we'll use to encode passwords
# http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
AppBundle\Entity\User: bcrypt
# http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
providers:
our_db_provider:
entity:
class: AppBundle:User
property: username
firewalls:
default:
anonymous: ~
http_basic: ~
provider: our_db_provider
form_login:
login_path: user_login
check_path: user_login_check
failure_path: user_login_fail
logout:
path: user_logout
target: homepage
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
access_control:
- { path: ^/admin, roles: ROLE_ADMIN}
# activate different ways to authenticate
# http_basic: ~
# http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate
# form_login: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
User Entity
<?php
namespace AppBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
/**
* User
*/
class User implements AdvancedUserInterface, \Serializable
{
/**
* #var int
*/
private $id;
/**
* #var string
*/
private $username;
/**
* #var string
*/
private $password;
/**
* #var string
*/
private $email;
/**
* #var bool
*/
private $isActive;
/**
* #var string
*/
private $plainPassword;
public function __construct() {
$this->setIsActive(TRUE);
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* #param string $username
*
* #return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set password
*
* #param string $password
*
* #return User
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* #return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Set email
*
* #param string $email
*
* #return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set isActive
*
* #param boolean $isActive
*
* #return User
*/
public function setIsActive($isActive)
{
$this->isActive = $isActive;
return $this;
}
/**
* Get isActive
*
* #return bool
*/
public function getIsActive()
{
return $this->isActive;
}
public function getRoles()
{
return array('ROLE_USER');
}
public function eraseCredentials()
{
}
public function serialize()
{
return serialize(array(
$this->id,
$this->username,
$this->password,
));
}
public function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
) = unserialize($serialized);
}
public function getSalt()
{
// The bcrypt algorithm doesn't require a separate salt.
// You *may* need a real salt if you choose a different encoder.
return null;
}
public function getPlainPassword()
{
return $this->plainPassword;
}
public function setPlainPassword($password)
{
$this->plainPassword = $password;
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
public function isEnabled()
{
return $this->isActive;
}
}
Thanks for your help.