我有Symfony 2.3项目。安装了FOS用户软件包和Sonata用户软件包。 现在我需要不仅通过用户名和密码登录用户,还需要通过卡号和PIN码登录。 用户只能有一张卡,但卡可以与多个用户连接。 并且算法是当用户输入他的用户名,密码,卡号和PIN时我应该检查所有数据,并且如果用户在他登录的数据库中有卡,但是如果卡信息有效但是输入的用户数据无效我应该在数据库中使用用户名和密码注册新用户并立即登录。
我创建了卡片实体,其中包含两个字段以及与用户实体的关系。用户实体已从Sonata User Bundle扩展。 这是卡实体代码:
namespace Acme\BoardBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Acme\UserBundle\Entity\User as User;
/**
* @ORM\Entity
* @ORM\Table(name="yam_card")
*/
class Card
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank()
* @Assert\Length(min = "6")
* @Assert\Length(max = "6")
*/
protected $number;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank()
* @Assert\Length(min = "4")
* @Assert\Length(max = "4")
*/
protected $pin;
/**
* @ORM\OneToMany(targetEntity="Acme\UserBundle\Entity\User", mappedBy="card", cascade={"remove"})
*/
protected $users;
public function __toString()
{
return (string)$this->number;
}
public function __construct()
{
$this->users = new ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set number
*
* @param string $number
*/
public function setNumber($number)
{
$this->number = $number;
}
/**
* Get number
*
* @return string
*/
public function getNumber()
{
return $this->number;
}
/**
* Set pin
*
* @param string $pin
*/
public function setPin($pin)
{
$this->pin = $pin;
}
/**
* Get pin
*
* @return string
*/
public function getPin()
{
return $this->pin;
}
/**
* Add users
*
* @param \Acme\UserBundle\Entity\User $users
* @return Card
*/
public function addUser(\Acme\UserBundle\Entity\User $users)
{
$this->users[] = $users;
return $this;
}
/**
* Remove users
*
* @param \Acme\UserBundle\Entity\User $users
*/
public function removeUser(\Acme\UserBundle\Entity\User $users)
{
$this->users->removeElement($users);
}
/**
* Get users
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
}
用户实体的代码和平关系:
namespace Acme\UserBundle\Entity;
use Sonata\UserBundle\Entity\BaseUser as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use \Acme\BoardBundle\Entity\Card;
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks
* @ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
...
protected $card;
/**
* Set card
*
* @param \Acme\BoardBundle\Entity\Card $card
* @return Card
*/
public function setCard(\Acme\BoardBundle\Entity\Card $card)
{
$this->card = $card;
return $this;
}
/**
* Get card
*
* @return \Acme\BoardBundle\Entity\Card
*/
public function getCard()
{
return $this->card;
}
}
User.orm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Acme\UserBundle\Entity\User" table="fos_user">
...
<many-to-one field="card" target-entity="Acme\BoardBundle\Entity\Card" inversed-by="users">
<join-column name="card" referenced-column-name="id" />
</many-to-one>
</entity>
</doctrine-mapping>
问题是我应该重新定义哪个类(或接口)来添加对两个附加参数(卡号和PIN)的检查以及如何制作它?
我找到了实现UserProviderInterface的UserProvider类。但是该类具有loadUserByUsername()方法,该方法按用户名加载用户并且已经使用用户对象。 该类没有收到响应对象,我可以从登录表单中获取卡号和PIN码。 此外,我找到了一个解决方案,通过从Symfony Security Core扩展UserChecker类来检查其他用户状态参数。有checkPreAuth和checkPostAuth方法,但我也可以使用User对象。 所以我想我应该使用一些监听器或类似的东西来检查请求中的接收用户名,密码,卡号和PIN码与我在DB中注册的用户是否相等。 但我找不到切入点。
答案 0 :(得分:0)
一旦确定传递的Card
有效且属于User
,您就可以手动登录用户。确保触发InteractiveLoginEvent
让所有听众都知道登录发生了:
// 'main' is the name of the firewall to login to
$token = new UsernamePasswordToken($validatedCard->getUser(), null, 'main', $validatedCard->getUser()->getRoles());
$this->get('security.token_storage')->setToken($token);
// Notify the dispatcher, so LoginListener is triggered
$loginEvent = new InteractiveLoginEvent($request, $token);
$this->get('event_dispatcher')->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent);