使用Symfony2我已经实现了一个AJAX操作来管理我的应用程序中的一些书签(添加/删除)。因此,用户需要进行身份验证才能继续。 我有一个解决方案,将用户重定向到登录页面,但我认为最好使用事件来处理此重定向。
实际解决方案:
检查用户的身份验证的方式与FOSUserBundle中的方式相同。
路由:
fbn_guide_manage_bookmark:
path: /bookmark/manage
defaults: { _controller: FBNGuideBundle:Guide:managebookmark }
options:
expose: true
requirements:
_method: POST
控制器:
public function manageBookmarkAction(Request $request)
{
if ($request->isXmlHttpRequest()) {
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
return new JsonResponse(array('status' => 'login'));
}
// DO THE STUFF
}
}
jQuery:
$(function() {
$('#bookmark').click(function() {
$.ajax({
type: 'POST',
url: Routing.generate('fbn_guide_manage_bookmark'),
data : xxxx, // SOME DATA
success: function(data) {
if (data.status == 'login') {
var redirect = Routing.generate('fos_user_security_login');
window.location.replace(redirect);
} else {
// DO THE STUFF
}
},
});
});
});
其他解决方案? :
为了不在控制器级验证用户是否经过身份验证,我会在安全配置文件中保护我的路由:
安全:
security:
access_control:
- { path: ^/(fr|en)/bookmark/manage, role: ROLE_USER }
控制器:
public function manageBookmarkAction(Request $request)
{
if ($request->isXmlHttpRequest()) {
$user = $this->getUser();
// THIS VERIFCATION SHOULD NOW BE REMOVED
/*
if (!is_object($user) || !$user instanceof UserInterface) {
return new JsonResponse(array('status' => 'login'));
}
*/
// DO THE STUFF
}
}
基本上,在尝试此解决方案时,Symfony2重定向内部登录页面,就像您在Firebug中看到的那样:
所以我的问题是:
我可以看到一些异常事件解决方案,但我认为有必要在控制器级别抛出异常,这是我想避免的。这是一个例子:
答案 0 :(得分:10)
这是一个解决方案(详见here):
安全性:
firewalls:
main:
pattern: ^/
anonymous: true
provider: fos_userbundle
entry_point: fbn_user.login_entry_point
#...
access_control:
- { path: ^/(fr|en)/bookmark/manage, role: ROLE_USER }
服务:
services:
fbn_user.login_entry_point:
class: FBN\UserBundle\EventListener\LoginEntryPoint
arguments: [ @router ]
服务类:
namespace FBN\UserBundle\EventListener;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* When the user is not authenticated at all (i.e. when the security context has no token yet),
* the firewall's entry point will be called to start() the authentication process.
*/
class LoginEntryPoint implements AuthenticationEntryPointInterface
{
protected $router;
public function __construct($router)
{
$this->router = $router;
}
/**
* This method receives the current Request object and the exception by which the exception
* listener was triggered.
*
* The method should return a Response object
*/
public function start(Request $request, AuthenticationException $authException = null)
{
if ($request->isXmlHttpRequest()) {
return new JsonResponse('',401);
}
return new RedirectResponse($this->router->generate('fos_user_security_login'));
}
}
jQuery:
$(function() {
$('#bookmark').click(function() {
// DATA PROCESSING
$.ajax({
type: 'POST',
url: Routing.generate('fbn_guide_manage_bookmark'),
data : xxxx, // SOME DATA,
success: function(data) {
// DO THE STUFF
},
error: function(jqXHR, textStatus, errorThrown) {
switch (jqXHR.status) {
case 401:
var redirectUrl = Routing.generate('fos_user_security_login');
window.location.replace(redirectUrl);
break;
case 403: // (Invalid CSRF token for example)
// Reload page from server
window.location.reload(true);
}
},
});
});
});
答案 1 :(得分:1)
是的,可以按照以下答案中的说明处理事件:https://stackoverflow.com/a/9182954/982075
使用HTTP状态代码401(未授权)或403(禁止)
您可以使用jquery中的error
函数来处理响应
$.ajax({
type: 'POST',
url: Routing.generate('fbn_guide_manage_bookmark'),
data : xxxx, // SOME DATA
error: function() {
alert("Your session has expired");
}
});
答案 2 :(得分:0)
我为Symf4解决了这个问题(不应该与其他人有很大不同)。异常侦听器将在重定向发生之前为POST提供JSON响应。在其他情况下,它仍将像往常一样重定向。您可以进一步自定义如何处理侦听器中的异常。
=============================================== ========
sevices:
exeption_listener:
class: Path\To\Listener\ExeptionListener
arguments: ['@security.token_storage']
tags:
- { name: kernel.event_listener, event: kernel.exception }
=============================================== ======
Listener/ExeptionListener.php
<?php
namespace Tensor\UserBundle\Listener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\JsonResponse;
class ExeptionListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
// return the subscribed events, their methods and priorities
return array(
KernelEvents::EXCEPTION => array(
array('processException', 10),
array('logException', 0),
array('notifyException', -10),
)
);
}
public function processException(GetResponseForExceptionEvent $event)
{
// ...
if (!$event->isMasterRequest()) {
// don't do anything if it's not the master request
return;
}
$request = $event->getRequest();
if( $request->getMethod() === 'POST' ){
$event->setResponse(new JsonResponse(array('error'=>$event->getException()->getMessage()), 403));
}
}
public function logException(GetResponseForExceptionEvent $event)
{
// ...
}
public function notifyException(GetResponseForExceptionEvent $event)
{
// ...
}
}