我搜索是否有一种简单的方法允许每个帐户仅使用 Symfony 3 进行一次会话?
目前,我使用PdoSessionHandler将会话存储在数据库中,并且我有一个该onSecurityInteractiveLogin事件的侦听器。当用户登录时,我在 User 对象中设置 sessionId,并将其保存在数据库中。
现在,我想做:当用户成功登录时,我也停用前一个会话,但是如何停用其他会话?在 Symfony 中,我可以为实际会话执行此操作,但不能为其他会话执行此操作...
否则,也许我可以处理 SQL 请求来删除先前的会话,但是随后,先前的用户丢失了会话中存储的所有内容,我只想断开他的连接。
另一种方法是相反的:对新用户说:“会话实际上是通过您的登录打开的,请断开与另一台计算机的连接。”,但如果用户只是关闭浏览器(不单击注销)并返回一些秒/分钟后使用记住我令牌,例如,他无法登录......并且必须等待几分钟。
如果有人有想法?
最后我做到了:
我有一个关于组织的问题:我有 2 位听众,这是最好的方式吗?或者我需要在一个文件中创建订阅者和组 2 事件,因为它具有相同的功能。
在我的 security.yml 中
logout:
path: /logout
target: /
invalidate_session: false
Run Code Online (Sandbox Code Playgroud)
invalidate_session: false,允许在注销时不破坏会话,然后我保留会话内容,并且当我强制用户注销时我可以添加一个flashbag。
我的服务声明:
app.event_listener.security_interactive_login:
class: AppBundle\EventListener\SecurityInteractiveLoginListener
arguments: ["@app.user_manager"]
tags:
- { name: kernel.event_listener, event: security.interactive_login }
app.event_listener.kernel_request:
class: AppBundle\EventListener\KernelRequestListener
arguments:
- "@security.token_storage"
- "@security.authorization_checker"
- "@session"
- "@router"
tags:
- { name: kernel.event_listener, event: kernel.request, priority: 0 }
Run Code Online (Sandbox Code Playgroud)
安全交互式登录监听器:
<?php
namespace AppBundle\EventListener;
use AppBundle\Utils\UserManager;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class SecurityInteractiveLoginListener
{
private $userManager;
public function __construct(UserManager $userManager)
{
$this->userManager = $userManager;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$request = $event->getRequest();
$session = $request->getSession();
$session->has('id'); // Just to fix a bug on Remember Me
$user = $event->getAuthenticationToken()->getUser();
// Set the session ID on user and save it in database
$user->setSessionId($session->getId());
$this->userManager->updateUser($user);
}
}
Run Code Online (Sandbox Code Playgroud)
内核请求监听器:
<?php
namespace AppBundle\EventListener;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
class KernelRequestListener
{
private $tokenStorage;
private $authorizationChecker;
private $session;
private $router;
public function __construct(
TokenStorage $tokenStorage,
AuthorizationChecker $authorizationChecker,
Session $session,
RouterInterface $router
) {
$this->tokenStorage = $tokenStorage;
$this->authorizationChecker = $authorizationChecker;
$this->session = $session;
$this->router = $router;
}
public function onKernelRequest(GetResponseEvent $event)
{
if (!$event->isMasterRequest() || !$this->isUserLoggedIn()) {
return;
}
$sessionId = $this->session->getId();
$user = $this->tokenStorage->getToken()->getUser();
// If the sessionId and the sessionId in database are equal: this is the latest connected user
if ($sessionId === $user->getSessionId()) {
return;
}
$this->session->getFlashBag()->add('danger', 'You have been logged out, because another person logged in whith your credentials.');
$redirectUrl = $this->router->generate('logout');
$response = new RedirectResponse($redirectUrl);
$event->setResponse($response);
}
protected function isUserLoggedIn()
{
try {
return $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED');
} catch (AuthenticationCredentialsNotFoundException $exception) {
// Ignoring this exception.
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2627 次 |
| 最近记录: |