Php Symfony2 AJAX登录
我举了一个例子,试图使用Symfony2和FOSUserBundle创建AJAX登录。我正在我的Php Symfony2 AJAX登录,php,symfony,fosuserbundle,Php,Symfony,Fosuserbundle,我举了一个例子,试图使用Symfony2和FOSUserBundle创建AJAX登录。我正在我的security.yml文件中的form\u login下设置我自己的success\u handler和failure\u handler 下面是课堂: class AjaxAuthenticationListener implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface {
security.yml
文件中的form\u login
下设置我自己的success\u handler
和failure\u handler
下面是课堂:
class AjaxAuthenticationListener implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface
{
/**
* This is called when an interactive authentication attempt succeeds. This
* is called by authentication listeners inheriting from
* AbstractAuthenticationListener.
*
* @see \Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener
* @param Request $request
* @param TokenInterface $token
* @return Response the response to return
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
if ($request->isXmlHttpRequest()) {
$result = array('success' => true);
$response = new Response(json_encode($result));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
/**
* This is called when an interactive authentication attempt fails. This is
* called by authentication listeners inheriting from
* AbstractAuthenticationListener.
*
* @param Request $request
* @param AuthenticationException $exception
* @return Response the response to return
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
if ($request->isXmlHttpRequest()) {
$result = array('success' => false, 'message' => $exception->getMessage());
$response = new Response(json_encode($result));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
}
这对于处理成功和失败的AJAX登录尝试非常有效。但是,如果启用,我将无法通过标准表单POST方法(非AJAX)登录。我收到以下错误:
Catchable致命错误:传递给Symfony\Component\HttpKernel\Event\GetResponseEvent::setResponse()的参数1必须是Symfony\Component\HttpFoundation\Response的实例,给定为空
我希望我的onAuthenticationSuccess
和onAuthenticationFailure
重写只对XmlHttpRequests(AJAX请求)执行,如果不执行,只需将执行交回原始处理程序即可
有办法做到这一点吗
TL;DR I希望AJAX请求的登录尝试返回JSON响应,无论成功还是失败,但我希望它不会影响通过form POST进行的标准登录。在这两种情况下(AJAX与否),您都必须返回响应对象。加上一个'else',你就可以开始了 默认实现是:
$response = $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request));
在
AbstractAuthenticationListener::onSuccess
中,我完全用javascript处理了这个问题:
namespace YourVendor\UserBundle\Handler;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
class AuthenticationHandler
implements AuthenticationSuccessHandlerInterface,
AuthenticationFailureHandlerInterface
{
private $router;
public function __construct(Router $router)
{
$this->router = $router;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
if ($request->isXmlHttpRequest()) {
// Handle XHR here
} else {
// If the user tried to access a protected resource and was forces to login
// redirect him back to that resource
if ($targetPath = $request->getSession()->get('_security.target_path')) {
$url = $targetPath;
} else {
// Otherwise, redirect him to wherever you want
$url = $this->router->generate('user_view', array(
'nickname' => $token->getUser()->getNickname()
));
}
return new RedirectResponse($url);
}
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
if ($request->isXmlHttpRequest()) {
// Handle XHR here
} else {
// Create a flash message with the authentication error message
$request->getSession()->setFlash('error', $exception->getMessage());
$url = $this->router->generate('user_login');
return new RedirectResponse($url);
}
}
}
if($('a.login').length > 0) { // if login button shows up (only if logged out)
var formDialog = new MyAppLib.AjaxFormDialog({ // create a new ajax dialog, which loads the loginpage
title: 'Login',
url: $('a.login').attr('href'),
formId: '#login-form',
successCallback: function(nullvalue, dialog) { // when the ajax request is finished, look for a login error. if no error shows up -> reload the current page
if(dialog.find('.error').length == 0) {
$('.ui-dialog-content').slideUp();
window.location.reload();
}
}
});
$('a.login').click(function(){
formDialog.show();
return false;
});
}
这是AjaxFormDialog类。不幸的是,我现在还没有将它移植到jQuery插件中 David's不错,但对新手来说,它缺少一点细节——所以这是为了填补空白
除了创建AuthenticationHandler之外,还需要使用创建处理程序的包中的服务配置将其设置为服务。默认的包生成会创建一个xml文件,但我更喜欢yml。下面是一个示例services.yml文件:
#src/Vendor/BundleName/Resources/config/services.yml
parameters:
vendor_security.authentication_handler: Vendor\BundleName\Handler\AuthenticationHandler
services:
authentication_handler:
class: %vendor_security.authentication_handler%
arguments: [@router]
tags:
- { name: 'monolog.logger', channel: 'security' }
您需要修改DependencyInjection捆绑包扩展以使用yml而不是xml,如下所示:
#src/Vendor/BundleName/DependencyInjection/BundleExtension.php
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
然后在应用程序的安全配置中,设置对刚才定义的身份验证处理程序服务的引用:
# app/config/security.yml
security:
firewalls:
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: /login
check_path: /login_check
success_handler: authentication_handler
failure_handler: authentication_handler
如果需要FOS UserBundle表单错误支持,必须使用:
$request->getSession()->set(SecurityContext::AUTHENTICATION_ERROR, $exception);
而不是:
$request->getSession()->setFlash('error', $exception->getMessage());
在第一个答案中
(当然记得标题:使用Symfony\Component\Security\Core\SecurityContext;)我为新用户制作了一个小捆绑包,以提供AJAX登录表单: 您只需在security.yml中通过ajax\u form\u login替换为form\u login身份验证即可
请随时在Github问题跟踪程序中推荐新功能 这可能不是OP所问的问题,但我遇到了这个问题,并认为其他人可能会遇到与我相同的问题 对于那些使用公认答案中描述的方法实现AJAX登录的人,以及使用AngularJS执行AJAX请求的人,默认情况下,这将不起作用。Angular的
$http
没有设置Symfony在调用$request->isXmlHttpRequest()
方法时使用的头。为了使用此方法,您需要在Angular请求中设置适当的标头。这就是我为解决这个问题所做的:
$http({
method : 'POST',
url : {{ path('login_check') }},
data : data,
headers: {'X-Requested-With': 'XMLHttpRequest'}
})
在使用此方法之前,请注意此标头不能很好地用于CORS。请参见,问题是我无法访问
$this->httpUtils
的实例。另外,我只想将执行传递回AbstractAuthenticationListener
-我不想将代码从中复制并粘贴到我的处理程序中。我希望您能找到一个好方法来执行,因为我和您一样被困在这一点上;-)我也有同样的问题。我在这里发布了一个问题:但目前没有答案:(这里有一篇很好的文章解释了如何做到这一点:这段代码由@elnur回答了我提出的一个类似问题。这是一个很好的回答-很抱歉没有看到您的类似问题。但是,我不会将其标记为已接受,因为我只想在当前请求是XMLHttpRequest时修改响应——否则,我会修改它。)想让Symfony假装我从未被拦截过。这是最简单的部分。你只需要返回一个包含你喜欢的内容的json响应,然后通过jquery阅读它。我认为最困难的是(遗憾的是没有记录)部分是非ajax登录处理程序。这是最好的答案,使用它我基本上可以完成我需要的-所以谢谢!注意,这个示例缺少以下内容,但我还没有编辑权限:-(使用Symfony\Component\Security\Core\Exception\AuthenticationException;services.yml配置中有一个输入错误。逗号(,)在频道之前需要。-{name:'monolog.logger',频道:'security'}谢谢这确实有助于填补Davids答案中的空白!好主意,即使它不干净(接受的答案是处理此问题的最佳方式),也会有帮助。