Symfony2 FOSbundle:记录每个用户登录日期
Symfony2 FOSbundle: record every user login date
如何在用户每次登录 Symfony2 时存储记录?
我创建了 UserLog 实体,我想在其中记录记录 ID、用户 ID 和登录日期。
我正在使用 FOS 用户包进行用户管理。我看到了只记录每个用户最后一次登录的问题 Symfony2 Login and Security ,但无法弄清楚如何记录每个登录日期
您需要覆盖默认的身份验证处理程序并在那里进行登录。
- 您需要为新的身份验证处理程序创建服务:
services.yml:
parameters:
fos_user_security.component.authentication.handler.login_success_handler.class: Path\To\New\Handler
services:
fos_user_security.component.authentication.handler.login_success_handler:
class: %fos_user_security.component.authentication.handler.login_success_handler.class%
arguments: [@router, @security.context]
tags:
- { name: 'monolog.logger', channel: 'security' }
- 创建处理程序并执行逻辑:
命名空间Application\Sonata\UserBundle\Services;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Router;
class LoginSuccessHandler implements AuthenticationSuccessHandlerInterface
{
protected $router;
protected $security;
public function __construct(Router $router, SecurityContext $security)
{
$this->router = $router;
$this->security = $security;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
if ($this->security->isGranted('ROLE_USER'))
// create your new entity and add the data you need
}
return $response;
}
在 security.yml 中你需要定义新的 success_handler,像这样:
main:
pattern: ^/
context: user
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /login
#use_forward: false
check_path: fos_user_security_check
success_handler: fos_user_security.component.authentication.handler.login_success_handler // the handler
#failure_path: null
always_use_default_target_path: false
default_target_path: profile
您必须实现一个 AuthenticationHandler
来侦听 onAuthenticationSuccess
事件。
首先,使用 getter 和 setter 在您的用户实体(日期时间,可为空)中创建 lastLogin
字段。
然后,创建如下:
<?php
namespace Acme\TestBundle\Handler;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\DependencyInjection\ContainerAware;
class AuthenticationHandler extends ContainerAware implements AuthenticationSuccessHandlerInterface
{
function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
$user = $token->getUser();
$lastLogin = new \DateTime();
$user->setLastLogin($lastLogin);
$this->container->get('doctrine')->getEntityManager()->flush();
// redirect the user for example
return new RedirectResponse($this->container->get('router')->generate('login_success'));
}
}
将其注册为服务:
// app/config/services.yml
services:
authentication_handler:
class: Acme\TestBundle\Handler\AuthenticationHandler
calls:
- [ setContainer, [ @service_container ] ]
并将其配置为身份验证 success_handler
:
// app/config/security.yml
# ...
form_login:
# ...
success_handler: authentication_handler
希望对您有所帮助。
编辑
我的错误,谢谢@JasonRoman。
创建一个包含 date
属性 的实体,例如 LoginRecord
,而不是 lastLogin
属性。
/**
* LoginRecord.
*
* @ORM\Entity
* @ORM\Table(name="user_logins")
*/
class LoginRecord
{
// Identifier
/** @ORM\Column(name="date", type="date") */
protected $date;
/**
* @ORM\ManyToOne(targetEntity="\Acme\TestBundle\Entity\User", inversedBy="loginRecords")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
*/
protected $user;
public function setDate($date)
{
$this->date = $date;
return $date;
}
public function getDate()
{
return $this->date;
}
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
public function getUser()
{
return $this->user;
}
}
然后,在您的用户实体中添加一个名为 $loginRecords
的 属性,表示与 LoginRecord
的一对多关联,如 targetClass
。
// User entity
class User
{
// ... Your other properties
/** @ORM\OneToMany(targetEntity="\Acme\TestBundle\Entity\LoginRecord", mappedBy="user", cascade={"persist", "remove"}) */
protected $loginRecords;
public function __construct()
{
// ...
$this->loginRecords = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addLoginRecord(LoginRecord $loginRecord)
{
$this->loginRecords[] = $loginRecord;
$loginRecord->setUser($this);
return $this;
}
public function removeLoginRecord(LoginRecord $loginRecord)
{
$this->loginRecords->removeElement($loginRecord);
}
public function getLoginRecords()
{
return $this->loginRecords;
}
}
并且,不要使用 setLastLogin
,而是使用 addLoginRecord($date)
在您的 AuthenticationHandler
中记录用户登录:
function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
$user = $token->getUser();
$lastLogin = new \DateTime();
$record = new LoginRecord();
$record->setDate($lastLogin);
$user->addLoginRecord($record);
$this->container->get('doctrine')->getEntityManager()->flush();
// redirect the user for example
return new RedirectResponse($this->container->get('router')->generate('login_success'));
}
Here is the solution for Symfony4.2
根据 Symfony documentation 必须监听 security.interactive_login
事件并创建 LoginListener
.
Code 1
app.login_listener:
class: App\EventListener\LoginListener
tags:
- { name: 'kernel.event_listener', event: 'security.interactive_login' }
Code 2
// src/EventListener/LoginListener.php
namespace App\EventListener;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class LoginListener
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
// Get the User entity.
$user = $event->getAuthenticationToken()->getUser();
// Update your field here.
$user->setLastLogin(new \DateTime());
// Persist the data to database.
$this->em->persist($user);
$this->em->flush();
}
}
One has to adjust this example to meet custom needs.
例如 LoginListener
归功于 Rihards Steinbergs
如何在用户每次登录 Symfony2 时存储记录?
我创建了 UserLog 实体,我想在其中记录记录 ID、用户 ID 和登录日期。
我正在使用 FOS 用户包进行用户管理。我看到了只记录每个用户最后一次登录的问题 Symfony2 Login and Security ,但无法弄清楚如何记录每个登录日期
您需要覆盖默认的身份验证处理程序并在那里进行登录。
- 您需要为新的身份验证处理程序创建服务:
services.yml:
parameters:
fos_user_security.component.authentication.handler.login_success_handler.class: Path\To\New\Handler
services:
fos_user_security.component.authentication.handler.login_success_handler:
class: %fos_user_security.component.authentication.handler.login_success_handler.class%
arguments: [@router, @security.context]
tags:
- { name: 'monolog.logger', channel: 'security' }
- 创建处理程序并执行逻辑:
命名空间Application\Sonata\UserBundle\Services;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Router;
class LoginSuccessHandler implements AuthenticationSuccessHandlerInterface
{
protected $router;
protected $security;
public function __construct(Router $router, SecurityContext $security)
{
$this->router = $router;
$this->security = $security;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
if ($this->security->isGranted('ROLE_USER'))
// create your new entity and add the data you need
}
return $response;
}
在 security.yml 中你需要定义新的 success_handler,像这样:
main: pattern: ^/ context: user form_login: provider: fos_userbundle csrf_provider: form.csrf_provider login_path: /login #use_forward: false check_path: fos_user_security_check success_handler: fos_user_security.component.authentication.handler.login_success_handler // the handler #failure_path: null always_use_default_target_path: false default_target_path: profile
您必须实现一个 AuthenticationHandler
来侦听 onAuthenticationSuccess
事件。
首先,使用 getter 和 setter 在您的用户实体(日期时间,可为空)中创建 lastLogin
字段。
然后,创建如下:
<?php
namespace Acme\TestBundle\Handler;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\DependencyInjection\ContainerAware;
class AuthenticationHandler extends ContainerAware implements AuthenticationSuccessHandlerInterface
{
function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
$user = $token->getUser();
$lastLogin = new \DateTime();
$user->setLastLogin($lastLogin);
$this->container->get('doctrine')->getEntityManager()->flush();
// redirect the user for example
return new RedirectResponse($this->container->get('router')->generate('login_success'));
}
}
将其注册为服务:
// app/config/services.yml
services:
authentication_handler:
class: Acme\TestBundle\Handler\AuthenticationHandler
calls:
- [ setContainer, [ @service_container ] ]
并将其配置为身份验证 success_handler
:
// app/config/security.yml
# ...
form_login:
# ...
success_handler: authentication_handler
希望对您有所帮助。
编辑
我的错误,谢谢@JasonRoman。
创建一个包含 date
属性 的实体,例如 LoginRecord
,而不是 lastLogin
属性。
/**
* LoginRecord.
*
* @ORM\Entity
* @ORM\Table(name="user_logins")
*/
class LoginRecord
{
// Identifier
/** @ORM\Column(name="date", type="date") */
protected $date;
/**
* @ORM\ManyToOne(targetEntity="\Acme\TestBundle\Entity\User", inversedBy="loginRecords")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
*/
protected $user;
public function setDate($date)
{
$this->date = $date;
return $date;
}
public function getDate()
{
return $this->date;
}
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
public function getUser()
{
return $this->user;
}
}
然后,在您的用户实体中添加一个名为 $loginRecords
的 属性,表示与 LoginRecord
的一对多关联,如 targetClass
。
// User entity
class User
{
// ... Your other properties
/** @ORM\OneToMany(targetEntity="\Acme\TestBundle\Entity\LoginRecord", mappedBy="user", cascade={"persist", "remove"}) */
protected $loginRecords;
public function __construct()
{
// ...
$this->loginRecords = new \Doctrine\Common\Collections\ArrayCollection();
}
public function addLoginRecord(LoginRecord $loginRecord)
{
$this->loginRecords[] = $loginRecord;
$loginRecord->setUser($this);
return $this;
}
public function removeLoginRecord(LoginRecord $loginRecord)
{
$this->loginRecords->removeElement($loginRecord);
}
public function getLoginRecords()
{
return $this->loginRecords;
}
}
并且,不要使用 setLastLogin
,而是使用 addLoginRecord($date)
在您的 AuthenticationHandler
中记录用户登录:
function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
$user = $token->getUser();
$lastLogin = new \DateTime();
$record = new LoginRecord();
$record->setDate($lastLogin);
$user->addLoginRecord($record);
$this->container->get('doctrine')->getEntityManager()->flush();
// redirect the user for example
return new RedirectResponse($this->container->get('router')->generate('login_success'));
}
Here is the solution for Symfony4.2
根据 Symfony documentation 必须监听 security.interactive_login
事件并创建 LoginListener
.
Code 1
app.login_listener:
class: App\EventListener\LoginListener
tags:
- { name: 'kernel.event_listener', event: 'security.interactive_login' }
Code 2
// src/EventListener/LoginListener.php
namespace App\EventListener;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class LoginListener
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
// Get the User entity.
$user = $event->getAuthenticationToken()->getUser();
// Update your field here.
$user->setLastLogin(new \DateTime());
// Persist the data to database.
$this->em->persist($user);
$this->em->flush();
}
}
One has to adjust this example to meet custom needs.
例如 LoginListener
归功于 Rihards Steinbergs