Symfony2 FOSbundle:记录每个用户的登录日期


Symfony2 FOSbundle: record every user login date

如何

存储用户每次登录Symfony2时的记录?

我创建了用户日志实体,我想在其中记录记录 ID、用户 ID 和登录日期。

我正在使用 FOS 用户捆绑包进行用户管理。我看到了只记录每个用户Symfony2登录和安全的最后一次登录的问题,但无法弄清楚如何记录每个登录日期

这是Symfony4.2的解决方案

根据Symfony文档,必须收听security.interactive_login事件并创建LoginListener

代码 1

app.login_listener:
    class: App'EventListener'LoginListener
    tags:
        - { name: 'kernel.event_listener', event: 'security.interactive_login' }

代码 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();
    }
}

必须调整此示例以满足自定义需求。

例如,LoginListener归功于Rihards Steinbergs

您必须实现一个侦听onAuthenticationSuccess事件的AuthenticationHandler

首先,在用户实体(日期时间、可为空)中创建 lastLogin 字段,其中包含 getter 和 setter。

然后,创建如下:

<?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'));
}

您需要覆盖默认的身份验证处理程序并在那里进行登录。

  1. 您需要为新的身份验证处理程序创建一个服务:

服务.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' }
  1. 创建处理程序并执行逻辑:
命名空间应用程序''

奏鸣曲''用户捆绑包''服务;

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;
    }
  1. 在 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