J'utilise FOS User Bundle et je dois utiliser une valeur appelée "maxLoginAttempts" à partir d'un enregistrement d'une autre entité / table que j'utilise pour mes paramètres.
L'entité s'appelle Paramètres. Ceci est mon code actuel et je voudrais changer le numéro 5 pour la valeur de la base de données.
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
/**
* @ORM\Entity
* @ORM\Table(name="`user`")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
protected $id;
...
public function isAccountNonLocked()
{
if($this->getLoginAttempts() >= 5) {
return false;
} else {
return true;
}
}
}
J'imagine quelque chose comme:
$this->em->getRepository('AppBundle:Parameters')
->findOneBy(['name' => 'maxLoginAttempts']);
Évidemment, pour le moment, je n'ai pas accès au référentiel. Comme je ne suis pas dans le contrôleur, je ne sais pas comment utiliser ces valeurs depuis l'intérieur d'une fonction d'une entité.
3 réponses
Enfin, la solution était de remplacer UserChecker en utilisant une autre fonction avec la même fonctionnalité.
<?php
namespace AppBundle\Checker;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Exception\CredentialsExpiredException;
use Symfony\Component\Security\Core\Exception\DisabledException;
use Symfony\Component\Security\Core\Exception\LockedException;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Security\Core\User\UserChecker as BaseUserChecker;
use Symfony\Component\Security\Core\User\UserInterface;
class UserChecker extends BaseUserChecker
{
private $em;
public function __construct( EntityManagerInterface $em)
{
$this->em = $em;
}
public function checkPreAuth(UserInterface $user)
{
//parent::checkPreAuth($user);
$maxMinutesLocked = $this->em->getRepository('AppBundle:Parameters')->findOneBy(array('name' => 'maxTimeLocked'))->getValue();
if (!$user instanceof AdvancedUserInterface) {
return;
}
//So I just added a new function called isAccountLocked() to the User Entity that's a copy from isAccountNonLocked() but I could add a paramater
if ($user->isAccountLocked($maxMinutesLocked)) {
$ex = new LockedException('User account is locked.');
$ex->setUser($user);
throw $ex;
}
if (!$user->isEnabled()) {
...
}
if (!$user->isAccountNonExpired()) {
...
}
}
public function checkPostAuth(UserInterface $user)
{
...
}
}
Je peux penser à une manière plus appropriée, à mon humble avis, de résoudre ceci:
L'entité User aura une propriété supplémentaire $ loginAttempts qui sera incrémentée par la méthode incrementLoginAttempts () chaque fois que la connexion échoue. Il sera initialisé à 0 via l'ORM et une méthode isLocked () nous dira si nous avons atteint 5 tentatives.
<?php
// AppBundle/Entity/User.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
/**
* @ORM\Entity
* @ORM\Table(name="`user`")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
protected $id;
public function __construct()
{
parent::__construct();
}
/**
* @ORM\Column(type="integer",options={"default"=0})
*/
private $loginAttempts;
...
public function getLoginAttempts()
{
return $this->loginAttemps;
}
public function incrementLoginAttempts()
{
if($this->loginAttempts<5){
$this->loginAttempts++;
}
return $this;
}
public function isLocked()
{
return ($this->loginAttempts == 5)
}
public function resetLoginAttempts()
{
$this->loginAttempts =0;
return $this;
}
Ensuite, créez un EventSubscriber pour l'événement SecuritySubscriber et déclenchez un incrementLoginAttempts () chaque fois que la connexion échoue; vérifier en même temps si l'utilisateur a déjà été verrouillé ou pas encore
<?php
// src/AppBundle/EventSubscriber/SecuritySubscriber.php
namespace AppBundle\EventSubscriber;
use AppBundle\Entity\User;
class SecuritySubscriber implements EventSubscriberInterface
{
private $entityManager;
private $tokenStorage;
private $authenticationUtils;
public function __construct(EntityManager $entityManager, TokenStorageInterface $tokenStorage, AuthenticationUtils $authenticationUtils)
{
$this->entityManager = $entityManager;
$this->tokenStorage = $tokenStorage;
$this->authenticationUtils = $authenticationUtils;
}
public static function getSubscribedEvents()
{
return array(
AuthenticationEvents::AUTHENTICATION_FAILURE => 'onAuthenticationFailure',
);
}
public function onAuthenticationFailure( AuthenticationFailureEvent $event )
{
$existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $username]);
if ($existingUser) {
$existingUser->incrementLoginAttempts();
$this->entityManager->persist($existingUser);
$this->entityManager->flush();
if($existingUser->isLocked()){
// Do your logic here
// Do not forget to un $existingUser->resetLoginAttempts() when necessary
}
}
}
}
N'oubliez pas d'enregistrer l'abonné en tant que service
# app/config/services.yml
services:
app.security.authentication_event_listener:
class: AppBundle\EventSubscriber\SecuritySubscriber
arguments:
- "@doctrine.orm.entity_manager"
- "@security.token_storage"
- "@security.authentication_utils"
P.S: Le code n'a pas été testé.
Vous avez probablement mal compris le concept d'une Entité:
La classe - souvent appelée "entité", c'est-à-dire une classe de base qui contient des données - est simple et permet de répondre aux exigences métier de besoin de produits dans votre application. Cette classe ne peut pas encore être conservée dans une base de données - c'est juste une simple classe PHP
Cela signifie que le Entity
n'est que le concept , donc vous ne pouvez pas avoir accès à l'autre Entities
ou au EntityManager
depuis l'intérieur de la classe.
Si vous souhaitez utiliser quelque chose comme la fonction membre que vous avez décrite. vous devez passer maxLoginAttempts
comme argument:
public function isAccountNonLocked($maxLoginAttempts)
{
if($this->getLoginAttempts() >= maxLoginAttempts) {
return false;
} else {
return true;
}
}
Dans ce cas, vous devez d'abord obtenir la valeur de maxLoginAttempts
à partir de votre configuration Entity
, puis l'utiliser sur l ' objet du User
que vous souhaitez vérifier:
$maxLoginAttempts = $this->em->getRepository('AppBundle:Parameters')
->findOneBy(['name' => 'maxLoginAttempts']);
$user = $this->em->getRepository('AppBundle:User')->find($userId);
if ($user->isAccountNonLocked($maxLoginAttempts)) {
// do something
}
De nouvelles questions
symfony
Symfony fait référence à la fois à un framework PHP pour la création d'applications Web ainsi qu'à un ensemble de composants sur lesquels le framework est construit. Cette balise fait référence aux principales versions 3.x, 4.x et 5.x actuellement prises en charge. Vous pouvez également spécifier une version exacte à l'aide de la balise correspondante. Cette balise ne doit pas être utilisée pour les questions sur Symfony 1.x. Veuillez utiliser la balise Symfony1 à la place.