我使用的是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中,所以我不确定应该如何从实体的函数内部使用这些值。
发布于 2017-12-04 14:48:55
最后,解决方案是使用具有相同功能的另一个函数覆盖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)
{
...
}
}
发布于 2017-11-28 11:52:01
您可能误解了实体的概念。
这个类--通常称为“实体”,意思是保存数据的基本类--非常简单,有助于满足应用程序中需要产品的业务需求。这个类还不能持久化到数据库--它只是一个简单的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
}
发布于 2017-12-01 00:41:45
我可以想出一个更恰当的方法来解决这个问题:
用户实体将有一个附加属性$loginAttempts,每次登录失败时,该属性将由incrementLoginAttempts()方法递增。它将通过ORM初始化为0,如果我们进行了5次尝试,一个方法isLocked()将告诉我们。
<?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;
}
然后,为该EventSubscriber事件创建一个SecuritySubscriber事件,并在每次登录失败时触发一个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"
这段代码还没有经过测试。
https://stackoverflow.com/questions/47528187
复制相似问题