allow only one connection on the same login with FOSUserBundle

岁酱吖の 提交于 2019-12-10 11:48:33

问题


I'm creating a website thanks to Symfony2 with FOSUserBundle.

I'm triyng to deny multiple connections on the same login (but from different computers for example). I've 2 solutions :

  • Create an event listner on authentification but I didn't manage to make it. (even with the cookbook).
  • override the login_check method but my FOSUserBundle doesn't work if I do it.

Do you have any better options? Or any solutions?


回答1:


Got it finaly. There is just one last update to make to solve it all. You need to add an other field to the User entity. sessionId (string). Then update your LoginListener class like that :

// YourSite\UserBundle\Listener\YourSiteLoginListener.php

//...
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
    $request = $event->getRequest();
    $session = $request->getSession();
    $user = $event->getAuthenticationToken()->getUser();
    $has_session = is_file ( '/path_to_your_php_session_file/'.'sess_'.$user->getSessionId() );

    if($user->getLogged() && $has_session){
        throw new AuthenticationException('this user is already logged');
    }else{
        $user->setLogged(true);
        $user->setSessionId($session->getId());
        $this->userManager->updateUser($user);
    }   
}



回答2:


Maybe this will help people to solve this problem.

It's kind of a solution but there is still a problem : If the user session is killed by php (after too mush time without action for example), you will have to go into your database to reset the "logged" value to 0.

So my solution is :

-add the field "logged" (boolean) to you User entity.

-in YourSite\UserBundle\Listener create a : YourSiteLoginListener.php with this code

namespace YourSite\UserBundle\Listener;

use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\SecurityContext;


class YourSiteLoginListener
{
private $userManager;

    public function __construct(UserManagerInterface $userManager)
    {
        $this->userManager = $userManager;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {   
        $user = $event->getAuthenticationToken()->getUser();

        if($user->getLogged()){
            throw new AuthenticationException('this user is already logged');
        }else{
            $user->setLogged(true);
            $this->userManager->updateUser($user);
        }   
    }
}

-then in the same directory, create a logout handler : YourSiteLogoutHandler.php

namespace YourSite\UserBundle\Listener;

use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;

class YourSiteLogoutHandler implements LogoutHandlerInterface
{
    private $userManager;

    public function __construct(UserManagerInterface $userManager)
    {
        $this->userManager = $userManager;
    }

    public function logout (Request $request, Response $response, TokenInterface $token){
        $user = $token->getUser();
        if($user->getLogged()){
            $user->setLogged(false);
            $this->userManager->updateUser($user);
        }
    }
}

-finaly declare those services in your app/config.yml for example:

services:
    yoursite_login_listener:
        class: YourSite\UserBundle\Listener\YourSiteLoginListener
        arguments: [@fos_user.user_manager]
        tags:
            - { name: kernel.event_listener, event: security.interactive_login, method :onSecurityInteractiveLogin }

    yoursite_logout_handler:
        class: YourSite\UserBundle\Listener\YourSiteLogoutHandler
        arguments: [@fos_user.user_manager]



回答3:


In Symfony3, the logout handler was not trigged by the code above. I rebuild the code so the system is updated when the user is logging out.

namespace YourSite\UserBundle\Listener;

use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;

class LogoutSuccessHandler implements LogoutSuccessHandlerInterface
{
    private $userManager;

    public function __construct(UserManagerInterface $userManager)
    {
        $this->userManager = $userManager;
    }


    public function onLogoutSuccess(Request $request){
        global $kernel;
        $user = $kernel->getContainer()->get('security.token_storage')->getToken()->getUser();
        if($user->getLogged()){
            $user->setLogged(false);
            $this->userManager->updateUser($user);
        }
        $referer = $request->headers->get('referer');

        return new RedirectResponse($referer);      
    }
}


来源:https://stackoverflow.com/questions/10615363/allow-only-one-connection-on-the-same-login-with-fosuserbundle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!