Skip to content

Instantly share code, notes, and snippets.

@janzenz
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janzenz/0b40bdc35bb029fc7eb9 to your computer and use it in GitHub Desktop.
Save janzenz/0b40bdc35bb029fc7eb9 to your computer and use it in GitHub Desktop.
imports:
- { resource: services.yml }
fos_user:
db_driver: orm
firewall_name: main
user_class: RentalPos\BookingBundle\Entity\SecurityUser
group:
group_class: RentalPos\BookingBundle\Entity\SecurityGroup
<?php
namespace RentalPos\BookingBundle\Security;
use FOS\UserBundle\Security\LoginManagerInterface;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Doctrine\Bundle\DoctrineBundle\Registry as Doctrine; // for Symfony 2.1.0+
/**
* Customises the Login Manager on FOSUserBundle
*
*/
class LoginManager implements LoginManagerInterface
{
private $securityContext;
private $userChecker;
private $sessionStrategy;
private $container;
private $em;
public function __construct(SecurityContextInterface $context, UserCheckerInterface $userChecker,
SessionAuthenticationStrategyInterface $sessionStrategy,
ContainerInterface $container,
Doctrine $doctrine)
{
$this->securityContext = $context;
$this->userChecker = $userChecker;
$this->sessionStrategy = $sessionStrategy;
$this->container = $container;
$this->em = $doctrine->getManager();
}
final public function loginUser($firewallName, UserInterface $user, Response $response = null)
{
$this->userChecker->checkPostAuth($user);
$token = $this->createToken($firewallName, $user);
if ($this->container->isScopeActive('request')) {
$this->sessionStrategy->onAuthentication($this->container->get('request'), $token);
if (null !== $response) {
$rememberMeServices = null;
if ($this->container->has('security.authentication.rememberme.services.persistent.'.$firewallName)) {
$rememberMeServices = $this->container->get('security.authentication.rememberme.services.persistent.'.$firewallName);
} elseif ($this->container->has('security.authentication.rememberme.services.simplehash.'.$firewallName)) {
$rememberMeServices = $this->container->get('security.authentication.rememberme.services.simplehash.'.$firewallName);
}
if ($rememberMeServices instanceof RememberMeServicesInterface) {
$rememberMeServices->loginSuccess($this->container->get('request'), $response, $token);
}
}
}
$this->securityContext->setToken($token);
// Here's the custom part, we need to get the current session and associate the user with it
$sessionId = $this->container->get('session')->getId();
// Just a test if indeed this Manager is called.
var_dump($sessionId);
exit;
$user->setSessionId($sessionId);
$this->em->persist($user);
$this->em->flush();
}
protected function createToken($firewall, UserInterface $user)
{
return new UsernamePasswordToken($user, null, $firewall, $user->getRoles());
}
}
services:
rentalpos.session.listener:
class: RentalPos\BookingBundle\Listener\SessionListener
arguments: ['@security.context', '@service_container', '@router']
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
fos_user.security.login_manager:
class: RentalPos\BookingBundle\Security\LoginManager
arguments: ['@security.context', '@security.user_checker', '@security.authentication.session_strategy', '@service_container', '@doctrine']
<?php
namespace RentalPos\BookingBundle\Listener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\Routing\Router;
/**
* Custom session listener.
*/
class SessionListener
{
private $securityContext;
private $container;
private $router;
public function __construct(SecurityContext $securityContext, Container $container, Router $router)
{
$this->securityContext = $securityContext;
$this->container = $container;
$this->router = $router;
}
public function onKernelRequest(GetResponseEvent $event)
{
// if (!$event->isMasterRequest()) {
// return;
// }
if ($token = $this->securityContext->getToken()) { // Check for a token - or else isGranted() will fail on the assets
if ($this->securityContext->isGranted('IS_AUTHENTICATED_FULLY') || $this->securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) { // Check if there is an authenticated user
// Compare the stored session ID to the current session ID with the user
if ($token->getUser() && $token->getUser()->getSessionId() !== $this->container->get('session')->getId()) {
// Tell the user that someone else has logged on with a different device
$this->container->get('session')->getFlashBag()->set(
'error',
'Another device has logged on with your username and password. To log back in again, please enter your credentials below. Please note that the other device will be logged out.'
);
// Kick this user out, because a new user has logged in
$this->securityContext->setToken(null);
// Redirect the user back to the login page, or else they'll still be trying to access the dashboard (which they no longer have access to)
$response = new RedirectResponse($this->router->generate('fos_user_security_login'));
$event->setResponse($response);
return $event;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment