我正在使用FOS用户包,我需要从我用于参数的另一个实体/表的记录中使用一个名为“maxLoginAttempts”的值。
实体它叫做参数。这是我当前的代码,我想从数据库中更改数字5的数字。
<?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;
}
}
}
我想象的是:
$this->em->getRepository('AppBundle:Parameters')
->findOneBy(['name' => 'maxLoginAttempts']);
显然现在我无法访问存储库。因为我不在Controller中,所以我不确定如何在实体的函数内使用这些值。
答案 0 :(得分:0)
您可能误解了Entity:
的概念该类 - 通常称为&#34;实体&#34;,意味着保存数据的基本类 - 很简单,有助于满足在您的应用程序中需要产品的业务需求。这个类还不能持久化到数据库 - 它只是一个简单的PHP类
这意味着Entity
只是概念,因此您无法访问其他Entities
或EntityManager
来自班级内部。
如果你想使用你所描述的成员函数之类的东西。你应该将maxLoginAttempts
作为arg传递:
public function isAccountNonLocked($maxLoginAttempts)
{
if($this->getLoginAttempts() >= maxLoginAttempts) {
return false;
} else {
return true;
}
}
在这种情况下,您需要先从配置maxLoginAttempts
获取Entity
的值,然后在您想要的User
的对象上使用它检查:
$maxLoginAttempts = $this->em->getRepository('AppBundle:Parameters')
->findOneBy(['name' => 'maxLoginAttempts']);
$user = $this->em->getRepository('AppBundle:User')->find($userId);
if ($user->isAccountNonLocked($maxLoginAttempts)) {
// do something
}
答案 1 :(得分:0)
我可以想出一个更合适的方式,恕我直言,来解决这个问题:
User实体将有一个额外的属性 $ loginAttempts ,每次登录失败时,它将通过incrementLoginAttempts()方法递增。它将通过ORM初始化为0,方法isLocked()将告诉我们是否已达到5次尝试。
<?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;
}
然后,为SecuritySubscriber事件创建一个EventSubscriber,并在每次登录失败时触发incrementLoginAttempts();同时检查用户是否已被锁定
<?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
}
}
}
}
不要忘记将订户注册为服务
# 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:代码尚未经过测试。
答案 2 :(得分:0)
最后,解决方案是使用具有相同功能的其他功能覆盖UserChecker。
<?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)
{
...
}
}