如果会话过期,则symfony 3 ajax重定向

时间:2017-11-22 15:50:29

标签: javascript symfony

在我使用的Symfony 3应用程序中,如果用户处于非活动状态一段时间,则会将其注销并请求再次登录。这是通过以下代码完成的:

//RequestListener.php

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

    if ($this->maxIdleTime > 0) {
        $lapse = time() - $this->session->getMetadataBag()->getCreated();
        $lapse_short = time() - $this->session->getMetadataBag()->getLastUsed();
        if ($lapse >= $this->maxIdleTime || $lapse_short >= $this->shortIdleTime) { 
            $username = $this->securityToken->getToken()->getUser();
            if ($username !== 'anon.'){
                $this->session->invalidate();
                $this->securityToken->setToken(null);
                $event->setResponse(new RedirectResponse($this->router->generate('login')));
            }
        }
    }
}

但是在重新加载页面时会发生重定向到登录表单的情况。我也想强制重定向每个ajax调用。默认情况下,我的ajax调用由以下地址提供:/ajax 但是当会话到期时,ajax被重定向'到我的登录页面地址和浏览器网络选项卡我看到以下内容:

my img

我应该重定向的ajax函数如下:

function requestAjax(json_data, url) {

  if(url.indexOf('login') !== -1){
    window.location = './login';
  }
    var request = $.ajax({ 
    url: root + '/' + url
    , method: 'post'
    , data: json_data
});
  return request;
}

但没有发生重定向。所以问题是如何强制重定向过期会话和ajax调用,以及为什么ajax状态为200但在这种情况下不说302?谢谢

UPD_1 我的services.yml RequestListener.php

app.handler.session_idle:
        class: AppBundle\EventListener\RequestListener
        arguments: ["@session", "@security.token_storage", "@router", "@app.logger", "%session_lifetime%", "%session_active_lifetime%", "%instance_path%"]
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

2 个答案:

答案 0 :(得分:0)

您可以尝试这样的(在Symfony 2.8中测试并使用)

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

class AjaxAuthenticationListener { 

/*
 * function onCoreException
 * Check if session is expired and handles security related exceptions  
 * @param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance
 * 
 */
public function onCoreException(GetResponseForExceptionEvent $event) {

    $exception = $event->getException();

    $event_request = $event->getRequest();

    $session = $event->getRequest()->getSession();

    if ($event_request->isXmlHttpRequest()) {

        if ($exception instanceof AuthenticationException || $exception instanceof AccessDeniedException) {

            $session->getFlashBag()->add('warning', 'You have been signed out automatically due to inactivity.');

            $event->setResponse(new Response('Session expired', 403));

        }
    }
}

}

正如您所看到的," onCoreException"函数返回403状态代码。

现在,在主页(在我的情况下)或将要进行ajax调用的页面中,您可以使用" ajaxError"并捕获jqXHR.status,如果它是403,则重定向到登录页面并使用" FlashBag"显示与过期会话相关的消息。

        $(document).ready(function () {
            //Catch AjaxAuthenticationListener response
            $(document).ajaxError(function (event, jqXHR) {
                if (403 === jqXHR.status) {
                    $(location).attr('href', '{{ path('login') }}');
                }
            });

我省略了解" onCoreException"函数作为一项服务以及它在过期时如何处理会话,同时考虑到这部分在你的代码中正常工作。

services.yml:

   app.gt.ajax.authentication.listener:
     class: AppBundle\EventListener\AjaxAuthenticationListener
     tags:
        - { name: kernel.event_listener, event: kernel.exception, method: onCoreException, priority: 1000 }

我希望这对你有用。

答案 1 :(得分:0)

Symfony 5解决方案

已经研究了这种护理了好几个小时。在symfony 5 How to Customize Access Denied Responses文档中,您可以自定义以下选项之一:

1. App entry point
2. Access denied handler
3. All Access Denied Responses

通过自定义All Access Denied Responses,我创建了一个kernel.exception订户/侦听器:

namespace App\EventSubscribers;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;


class AccessDeniedHandler implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            // the priority must be greater than the Security HTTP
            // ExceptionListener, to make sure it's called before
            // the default exception listener
            KernelEvents::EXCEPTION => ['onKernelException', 2]
        ];
    }


    public function onKernelException(ExceptionEvent $event): void
    {
        // Ajax is returning login page instead of session expired/access denied
        // Creating a custom handler for ajax
        // more at https://symfony.com/doc/current/security/access_denied_handler.html#customize-the-unauthorized-response

        $request = $event->getRequest();
        if($request->isXmlHttpRequest()){
            $event->setResponse(new Response('Your session has expired!', 403));
            return;
        }
    }
}