Session 如何在一段时间不活动后自动注销用户?

Session 如何在一段时间不活动后自动注销用户?,session,symfony,Session,Symfony,在网络上进行了大量搜索,但什么也没找到之后,我想知道是否有一种简单的方法可以让用户在一段不活动的时间后通过Symfony Security自动注销。例如,我希望用户在30分钟不活动后注销 我使用自定义用户提供程序,如 但在用户登录到系统后,会话永远不会过期。即使他在几天后关闭浏览器并再次打开,会话仍然有效 无论如何,是否可以通过自动方式甚至手动方式注销此用户? 我该怎么做呢?关于: #app/config/config.yml framework: session: co

在网络上进行了大量搜索,但什么也没找到之后,我想知道是否有一种简单的方法可以让用户在一段不活动的时间后通过Symfony Security自动注销。例如,我希望用户在30分钟不活动后注销

我使用自定义用户提供程序,如

但在用户登录到系统后,会话永远不会过期。即使他在几天后关闭浏览器并再次打开,会话仍然有效

无论如何,是否可以通过自动方式甚至手动方式注销此用户? 我该怎么做呢?

关于:

#app/config/config.yml
framework:
    session:
        cookie_lifetime:       1800

您必须使用内核侦听器来实现它,这是我解决它的方法:

Listenersrc/Comakai/MyBundle/Handler/SessionIdleHandler.php Configsrc/Comakai/MyBundle/Resources/Config/services.yml(Comakai/MyBundle/DependencyInjection/MyBundleExtension.php)

现在,您可以在parameters.yml中将
会话\u max\u idle\u time设置为30*60=1800秒(或者在需要的任何地方硬编码该值):

参数app/config/Parameters.yml


以下设置将注销不活动超过30分钟的用户。如果每29分钟发出一次请求,他们将永远不会注销。请注意,这在本地环境中不容易测试,因为垃圾收集器只从您的请求中调用,因此永远不会到达gc_maxlifetime

#app/config/config.yml
session:
    cookie_lifetime: 86400
    gc_maxlifetime: 1800
如果打开更多浏览器/会话并使用以下配置,则可以测试此功能:

#app/config/config.yml
session:
    cookie_lifetime: 86400
    gc_maxlifetime: 1800
    gc_probability: 1
    gc_divisor: 1
希望有帮助

请注意,添加:

 session:
    gc_probability: 1
    gc_divisor: 1

仅用于在本地环境中测试垃圾收集器,在本地环境中没有其他请求导致垃圾收集器删除您的会话。在生产环境中,让垃圾收集器在每个请求上运行并不意味着(或必要的)

非常适合FOSUserbundle,谢谢

我将其添加到内部条件中,以防止匿名用户注销

...

$isFullyAuthenticated = $this->securityContext->isGranted('IS_AUTHENTICATED_FULLY');

if ($lapse > $this->maxIdleTime && $isFullyAuthenticated == true) {

 ... do logout / redirect etc.

}

在Symfony 2.4中,在1小时的暂停时间内,以下各项对我来说效果良好:

framework:
    #esi:             ~
    translator:      { fallback: %locale% }
    secret:          %secret%
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
        strict_requirements: ~
        http_port: 80
        https_port: 443
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    templating:
        engines: ['twig']
        #assets_version: SomeVersionScheme
    default_locale:  "%locale%"
    trusted_proxies: ~
    session:         
        cookie_lifetime:       3600
    fragments:       ~
    trusted_hosts:   ~

cookie生存期不合适,因为它可以被操纵 由客户端执行,因此我们必须在服务器端执行到期。最简单的方法是通过合理频繁地运行的垃圾收集来实现这一点。cookie_生存期将设置为相对较短的时间 高值,垃圾收集gc_maxlifetime将设置为在任何时间销毁会话 所需的怠速周期为

framework:
    #esi:             ~
    #translator:      { fallback: "%locale%" }
    secret:          "%secret%"
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
        strict_requirements: ~
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    templating:
        engines: ['twig']
        #assets_version: SomeVersionScheme
    default_locale:  "%locale%"
    trusted_hosts:   ~
    trusted_proxies: ~
    session:
        # handler_id set to null will use default session handler from php.ini
        #handler_id:  ~
        cookie_lifetime: 9999
        gc_maxlifetime: 900
        gc_probability: 1
        gc_divisor: 2
    fragments:       ~
    http_method_override: true

如果有人想在Symfony 4中实现这一点,我已经更新了@coma给出的答案,因为security.context被贬低了,parameters.yml现在只是app/config/service.yaml的一部分,您可以为构造函数注入其他变量。不过,答案基本相同,只是对Symfony 4进行了调整:

Listenersrc/Security/SessionIdleHandler.php(或任何地方,它都映射到下面的事件侦听器中)

内核事件侦听器app/config/service.yaml

parameters:
    ...
    session_max_idle_time: 600 // set to whatever value you want in seconds
services:
    ...
    App.Handler.SessionIdle:
        class: App\Security\SessionIdleHandler
        arguments: ['%session_max_idle_time%']
        tags: [{ name: kernel.event_listener, event: kernel.request }]

下面是我使用Symfony 4的示例

使用了会话而不是SessionInterface,因为此接口 不包含对
getFlashBag()
方法的访问

重定向是在
app\u登录时执行的,而不是在
app\u注销时执行的,
否则,当前会话的flashBag将丢失

$this->tokenStorage->setToken()可以替换为
$this->tokenStorage->reset()通过具体类但是
接口不允许这样做

你可以用这个:

一个简单的重定向,可以在布局中使用小树枝在片刻后注销
首先创建细枝扩展
#App/Twig/LogoutAfterMomentExtension.php

我试过这个。对我不起作用。我收到以下错误
InvalidConfigurationException:无法识别的选项“framework.session”下的“lifetime”
。我正在使用Symfony v.2.3.4try和
cookie\u lifetime
而不是
lifetime
谢谢您的帖子..Kinldy告诉我如何通过parameters.yml中的session\u max\u idle\u time值?您将如何为此编写集成测试@用户3746259,我认为单元测试就足够了,因为剩下的已经由Symfony的人测试过了,但是无论如何,我想你可以尝试在很短的时间内配置它,做一个登录调用,然后再做一个调用,并断言最后一个调用会被重定向。看起来有人做了一个捆绑包来做这件事:@Brian,有趣的是,我一直从中获得支持,而我已经有两年没有写过一行PHP了。我很确定这是正确的解决方案,您不必定义服务来执行此操作,它也在文档中:注意:这只会在到期后的第二个请求中注销用户,因为gc似乎是在请求后调用的。如果你有一个高流量的站点,这很好,但是对于低流量的站点,这并不是很好。gc会在每次请求时随机调用,它被调用的概率是session.gc_probability/session.gc_divisior,当你把gc_probability=1和gc_divisior=1时,概率是1,这个解决方案会很好地工作,但它确实不是一个有效的解决方案,因为每次请求都会调用gc…哎哟,这种解决方案确实是不对的:在每个请求上运行垃圾收集器会立即杀死一台高流量服务器(甚至会大大降低具有复杂应用程序的低流量服务器的速度),但最重要的是,这种解决方案并不安全:cookie时间可以由用户操纵。考虑使用@昏迷的解决方案,如在使用GCII概率的回答中提到的:1只是在本地/测试环境中测试它的一种方式,而不是用于生产环境。如果你不担心用户操纵cookie时间(就像我一样),我仍然不会
framework:
    #esi:             ~
    #translator:      { fallback: "%locale%" }
    secret:          "%secret%"
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
        strict_requirements: ~
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    templating:
        engines: ['twig']
        #assets_version: SomeVersionScheme
    default_locale:  "%locale%"
    trusted_hosts:   ~
    trusted_proxies: ~
    session:
        # handler_id set to null will use default session handler from php.ini
        #handler_id:  ~
        cookie_lifetime: 9999
        gc_maxlifetime: 900
        gc_probability: 1
        gc_divisor: 2
    fragments:       ~
    http_method_override: true
<?php

namespace App\Security;

use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class SessionIdleHandler
{

    protected $session;
    protected $securityToken;
    protected $router;
    protected $maxIdleTime;

    public function __construct($maxIdleTime, SessionInterface $session, TokenStorageInterface $securityToken, RouterInterface $router)
    {
        $this->session = $session;
        $this->securityToken = $securityToken;
        $this->router = $router;
        $this->maxIdleTime = $maxIdleTime;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) {

            return;
        }

        if ($this->maxIdleTime > 0) {

            $this->session->start();
            $lapse = time() - $this->session->getMetadataBag()->getLastUsed();

            if ($lapse > $this->maxIdleTime) {

                $this->securityToken->setToken(null);
                $this->session->getFlashBag()->set('info', 'You have been logged out due to inactivity.');

                // logout is defined in security.yaml.  See 'Logging Out' section here:
                // https://symfony.com/doc/4.1/security.html
                $event->setResponse(new RedirectResponse($this->router->generate(logout)));
            }
        }
    }
}
parameters:
    ...
    session_max_idle_time: 600 // set to whatever value you want in seconds
services:
    ...
    App.Handler.SessionIdle:
        class: App\Security\SessionIdleHandler
        arguments: ['%session_max_idle_time%']
        tags: [{ name: kernel.event_listener, event: kernel.request }]
App\EventListener\SessionIdleListener:
    bind:
        $maxIdleTime: '%env(APP_SESSION_MAX_IDLE_TIME)%'
        $session: '@session'
    tags:
        - { name: kernel.event_listener, event: kernel.request }
#App/Twig/LogoutAfterMomentExtension.php  

<?php


namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class LogoutAfterMomentExtension extends AbstractExtension
{
    public function getFunctions()
    {
        return [
            new TwigFunction('logoutAfter', [$this, 'logoutAfter']),
        ];
    }

    public function logoutAfter(int $seconds)
    {
        return header( "refresh:".$seconds.";url=/admin/logout" );
    }

}
#templates/layout.html.twig

<body>

{{ logoutAfter(5) }} #it will logout after 5 seconds
...

</body>