在我使用的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被重定向'到我的登录页面地址和浏览器网络选项卡我看到以下内容:
我应该重定向的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 }
答案 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 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;
}
}
}