可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to return all Logged in users of my application and render it in my Dashboard. The user_id
and user_name
should be retrieved from the session (I am using an external LDAP Library for authentication)
I have created a field in the database called lastActivity
which will contain the last login time and then I can query the database for lastActivity
display users logged in in the last 2 minutes.
ActivityListener.php
<?php
namespace Bnpp\SecurityBundle\EventListener;
use Doctrine\ORM\EntityManager;
//use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Acme\SecurityBundle\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Registry;
/**
* Listener that updates the last activity of the authenticated user
*/
class ActivityListener
{
protected $securityContext;
protected $entityManager;
public function __construct(SecurityContext $securityContext, EntityManager $entityManager)
{
$this->securityContext = $securityContext;
$this->entityManager = $entityManager;
}
/**
* Update the user "lastActivity" on each request
* @param FilterControllerEvent $event
*/
public function onCoreController(FilterControllerEvent $event)
{
// Check that the current request is a "MASTER_REQUEST"
// Ignore any sub-request
if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) {
return;
}
// Check token authentication availability
if ($this->securityContext->getToken()) {
$user = $this->securityContext->getToken()->getUser();
if ( ($user instanceof User) && !($user->isActiveNow()) ) {
$user->setLastActivity(new \DateTime('now'));
$this->entityManager->flush($user);
}
}
}
}
Services.yml
services:
activity_listener:
class: Bnpp\SecurityBundle\EventListener\ActivityListener
arguments: [@security.context, @doctrine.orm.entity_manager]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onCoreController }
User Entity
<?php
namespace Acme\SecurityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* User
*
* @ORM\Table(name="users")
* @ORM\Entity(repositoryClass="Acme\SecurityBundle\Entity\UserRepository")
*/
class User implements UserInterface
{
/**
* @var \DateTime
* @ORM\Column(name="LASTACTIVITY", type="datetime")
*/
private $lastActivity;
/**
* @return bool whether the user is active or not
*/
public function isActiveNow()
{
$delay = new\DateTime('2 minutes ago');
return($this->getlastActivity()>$delay);
}
/**
* Set lastActivity
*
* @param\Datetime $lastActivity
* @return User
*/
public function setlastActivity($lastActivity)
{
$this->lastActivity = $lastActivity;
return $this;
}
/**
* Get lastActivity
*
* @return \DateTime
*/
public function getlastActivity()
{
return $this->lastActivity;
}
}
回答1:
There is a great post here: List online users.
You can create a Listener that listens on the kernel.controller
event and updates a user field lastActivity every time a user is active. You can check lastActivity < now()- 2 minutes
and update lastActivity timestamp.
Also: Implementing user activity in symfony 2
Here is how to do it
Note: If you're not using FOSUserBundle, see Edit below.
1 Add this to your User Entity
/**
* Date/Time of the last activity
*
* @var \Datetime
* @ORM\Column(name="last_activity_at", type="datetime")
*/
protected $lastActivityAt;
/**
* @param \Datetime $lastActivityAt
*/
public function setLastActivityAt($lastActivityAt)
{
$this->lastActivityAt = $lastActivityAt;
}
/**
* @return \Datetime
*/
public function getLastActivityAt()
{
return $this->lastActivityAt;
}
/**
* @return Bool Whether the user is active or not
*/
public function isActiveNow()
{
// Delay during wich the user will be considered as still active
$delay = new \DateTime('2 minutes ago');
return ( $this->getLastActivityAt() > $delay );
}
2 Create Event Listener
<?php
namespace Acme\UserBundle\EventListener;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Model\UserInterface;
/**
* Listener that updates the last activity of the authenticated user
*/
class ActivityListener
{
protected $securityContext;
protected $userManager;
public function __construct(SecurityContext $securityContext, UserManagerInterface $userManager)
{
$this->securityContext = $securityContext;
$this->userManager = $userManager;
}
/**
* Update the user "lastActivity" on each request
* @param FilterControllerEvent $event
*/
public function onCoreController(FilterControllerEvent $event)
{
// Check that the current request is a "MASTER_REQUEST"
// Ignore any sub-request
if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) {
return;
}
// Check token authentication availability
if ($this->securityContext->getToken()) {
$user = $this->securityContext->getToken()->getUser();
if ( ($user instanceof UserInterface) && !($user->isActiveNow()) ) {
$user->setLastActivityAt(new \DateTime());
$this->userManager->updateUser($user);
}
}
}
}
3 Declare event Listener as a service
parameters:
acme_user.activity_listener.class: Acme\UserBundle\EventListener\ActivityListener
services:
acme_user.activity_listener:
class: %acme_user.activity_listener.class%
arguments: [@security.context, @fos_user.user_manager]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onCoreController }
And you're good to go!
Edit (without FOSUserBundle)
1 Add this to your User Entity
Same as Step 1 Above
2 Create Event Listener
<?php
namespace Acme\UserBundle\EventListener;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Doctrine\ORM\EntityManager;
use Acme\UserBundle\Entity\User;
/**
* Listener that updates the last activity of the authenticated user
*/
class ActivityListener
{
protected $securityContext;
protected $entityManager;
public function __construct(SecurityContext $securityContext, EntityManager $entityManager)
{
$this->securityContext = $securityContext;
$this->entityManager = $entityManager;
}
/**
* Update the user "lastActivity" on each request
* @param FilterControllerEvent $event
*/
public function onCoreController(FilterControllerEvent $event)
{
// Check that the current request is a "MASTER_REQUEST"
// Ignore any sub-request
if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) {
return;
}
// Check token authentication availability
if ($this->securityContext->getToken()) {
$user = $this->securityContext->getToken()->getUser();
if ( ($user instanceof User) && !($user->isActiveNow()) ) {
$user->setLastActivityAt(new \DateTime());
$this->entityManager->flush($user);
}
}
}
}
3 Declare event Listener as a service
parameters:
acme_user.activity_listener.class: Acme\UserBundle\EventListener\ActivityListener
services:
acme_user.activity_listener:
class: %acme_user.activity_listener.class%
arguments: [@security.context, @doctrine.orm.entity_manager]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onCoreController }
And you're good to go!
回答2:
As I can't comment on posts, I'd still like to give a remark on the answer by Mick via this answer.
Since Symfony 2.6 the SecurityContext class is deprecated and, in this case, the TokenStorage class should be used instead.
Thus, the services.yml would be as follows:
services:
acme_user.activity_listener:
class: %acme_user.activity_listener.class%
arguments: ['@security.token_storage', '@doctrine.orm.entity_manager']
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onCoreController }
And, instead of
use Symfony\Component\Security\Core\SecurityContext;
One should
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
(also replace the SecurityContext inside the class with the TokenStorage class)
Then, on line 38, the token availability would be checked using
$this->tokenStorage->getToken()
And, on line 39, the user instance would be obtained using
$this->tokenStorage->getToken()->getUser()
回答3:
Update for Symfony 3.4
1. Add this to your User Entity
Same as Step 1 Above
2. Create Event Listener
<?php
namespace Acme\UserBundle\EventListener;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Doctrine\ORM\EntityManager;
use Acme\UserBundle\Entity\User;
/**
* Listener that updates the last activity of the authenticated user
*/
class ActivityListener
{
protected $tokenContext;
protected $doctrine;
public function __construct(TokenyContext $tokenContext, $doctrine)
{
$this->tokenContext= $tokenContext;
$this->doctrine= $doctrine;
}
/**
* Update the user "lastActivity" on each request
* @param FilterControllerEvent $event
*/
public function onCoreController(FilterControllerEvent $event)
{
// Check that the current request is a "MASTER_REQUEST"
// Ignore any sub-request
if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) {
return;
}
// Check token authentication availability
if ($this->tokenContext->getToken()) {
$user = $this->tokenContext->getToken()->getUser();
if ( ($user instanceof User) && !($user->isActiveNow()) ) {
$user->setLastActivityAt(new \DateTime());
$this->doctrine->getManager()->flush($user);
}
}
}
}
3. Declare event Listener as a service
parameters:
acme_user.activity_listener.class: Acme\UserBundle\EventListener\ActivityListener
services:
acme_user.activity_listener:
class: %acme_user.activity_listener.class%
arguments: ['@security.token_storage', '@doctrine']
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onCoreController }
回答4:
For Symfony3.4 (4), I used EntityManagerInterface to update user, and Security to get user, following codes worked for me :
app/config/services.yml
AppBundle\Service\ActivityListener:
tags:
- { name: 'kernel.event_listener', event: 'kernel.controller', method: onCoreController }
Service/ActivityListener.php
<?php
namespace AppBundle\Service;
use AppBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\Security\Core\Security;
class ActivityListener
{
private $em;
private $security;
public function __construct(EntityManagerInterface $em, Security $security)
{
$this->em = $em;
$this->security = $security;
}
public function onCoreController(FilterControllerEvent $event)
{
// Check that the current request is a "MASTER_REQUEST"
// Ignore any sub-request
if ($event->getRequestType() !== HttpKernel::MASTER_REQUEST) {
return;
}
// Check token authentication availability
if ($this->security->getToken()) {
$user = $this->security->getToken()->getUser();
if ( ($user instanceof User) && !($user->isActiveNow()) ) {
$user->setLastActivityAt(new \DateTime());
$this->em->flush($user);
}
}
}
}