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

Symfony2 FOSbundle: record every user login date

如何在用户每次登录 Symfony2 时存储记录?

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

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

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

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

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' }
  1. 创建处理程序并执行逻辑:

命名空间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;
    }
  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
    

您必须实现一个 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