AJAX 的 Symfony 2.3 和 FOSUserBundle 不断抛出 CSRF 错误
Symfony 2.3 and FOSUserBundle with AJAX keeps throwing CSRF-Errors
我正在使用带有 FOSUserBundle 的 Symfony 2.3,并希望使用 AJAX 创建一个登录表单。我在 SO 上找到了一个视图问题(比如 this one) and even some other helpful sites (Adding an AJAX Login Form to a Symfony Project),它解释了如何将 FOSUserBundle 与 ajax.
一起使用
当我定期提交表单时一切正常,但是使用 ajax 调用我不断收到消息 "Invalid CSRF token."。
这是我的配置:
自定义身份验证处理程序:
namespace Moodio\Bundle\UserBundle\Handler;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
class AuthenticationHandler implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface
{
private $router;
private $session;
private $translator;
private $csrf_provider;
/**
* Constructor
*/
public function __construct( RouterInterface $router, Session $session, $translator, $csrf_provider )
{
$this->router = $router;
$this->session = $session;
$this->translator = $translator;
$this->csrf_provider = $csrf_provider;
}
/**
* onAuthenticationSuccess
*/
public function onAuthenticationSuccess( Request $request, TokenInterface $token )
{
// if AJAX login
if ( $request->isXmlHttpRequest() ) {
$array = array( 'success' => true); // data to return via JSON
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
} else {// if form login
return parent::onAuthenticationSuccess($request, $token);
}
}
/**
* onAuthenticationFailure
*
*/
public function onAuthenticationFailure( Request $request, AuthenticationException $exception )
{
// if AJAX login
if ( $request->isXmlHttpRequest() ) {
$result = array(
'success' => false,
'message' => $this->translator->trans($exception->getMessage(), array(), 'FOSUserBundle')
); // data to return via JSON
$response = new Response( json_encode( $result ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
} else {// if form login
// set authentication exception to session
$request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception);
return new RedirectResponse( $this->router->generate( 'fos_user_security_login' ) );
}
}
}
src/Moodio/Bundle/MainBundle/services.yml:
services:
moodio_main.security.authentication_handler:
class: Moodio\Bundle\UserBundle\Handler\AuthenticationHandler
public: false
arguments:
- @router
- @session
- @translator
- @form.csrf_provider
security.yml 防火墙:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
success_handler: moodio_main.security.authentication_handler
failure_handler: moodio_main.security.authentication_handler
logout: true
anonymous: true
我的javascript
$('#_submit').click(function(e){
e.preventDefault();
var frm = $('form');
$.ajax({
type : frm.attr('method'),
url : frm.attr('action'),
data : frm.serialize(),
success : function(data, status, object) {
if(data.error) $('.error').html(data.message);
},
error: function(data, status, object){
console.log(data.message);
}
});
});
我尝试了 this answer 中的一些答案,但它对我不起作用。我实际上不明白为什么它会有所作为,因为 FOSUserBundle 已经创建了 csrf-token 并使用 {{ csrf_token }}.
将其包含在 twig 模板中
目前我正在使用标准的 FOSUserBundle 模板(并且只添加了 ajax 所需的 js 视图行)。
我还尝试过一件事,看看 csrf 验证是否有效,即在 onAuthenticationFailure 函数中生成 csrf 令牌,并在下一行检查它是否有效。在这种情况下,isCsrfTokenValid() 返回 true。
当我在防火墙中(在 security.yml 中)停用 csrf_provider 时,我总是收到消息 "Bad credentials",即使凭据是正确的。
如果您使用的是最新版本的 FOSUserBundle,则 csrf 提供程序已更改为 security.csrf.token_manager。您的表单可能正在使用 form.csrf_provider 生成令牌,而 FOSUB 可能正在使用另一个。或者:
- 将您的 FOSUserBundle 依赖项明确设置为 1.2 或 1.3,而不是 dev-master
- 手动将 csrf 提供程序设置为正确的服务。
无论哪种方式,请清除您的 cookie 并重新启动您的开发服务器以确保其中没有遗留信息。
我终于可以解决我的问题了:
我发现 Divi-AjaxLoginBundle 非常有用。我不确定问题出在哪里,因为我实际上有与此捆绑包相同的 AuthenticationHandlers,但 DependencyInjection 文件夹中也有一些文件可能完成了工作。
感谢所有帮助过我的人。
我正在使用带有 FOSUserBundle 的 Symfony 2.3,并希望使用 AJAX 创建一个登录表单。我在 SO 上找到了一个视图问题(比如 this one) and even some other helpful sites (Adding an AJAX Login Form to a Symfony Project),它解释了如何将 FOSUserBundle 与 ajax.
一起使用当我定期提交表单时一切正常,但是使用 ajax 调用我不断收到消息 "Invalid CSRF token."。
这是我的配置:
自定义身份验证处理程序:
namespace Moodio\Bundle\UserBundle\Handler;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
class AuthenticationHandler implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface
{
private $router;
private $session;
private $translator;
private $csrf_provider;
/**
* Constructor
*/
public function __construct( RouterInterface $router, Session $session, $translator, $csrf_provider )
{
$this->router = $router;
$this->session = $session;
$this->translator = $translator;
$this->csrf_provider = $csrf_provider;
}
/**
* onAuthenticationSuccess
*/
public function onAuthenticationSuccess( Request $request, TokenInterface $token )
{
// if AJAX login
if ( $request->isXmlHttpRequest() ) {
$array = array( 'success' => true); // data to return via JSON
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
} else {// if form login
return parent::onAuthenticationSuccess($request, $token);
}
}
/**
* onAuthenticationFailure
*
*/
public function onAuthenticationFailure( Request $request, AuthenticationException $exception )
{
// if AJAX login
if ( $request->isXmlHttpRequest() ) {
$result = array(
'success' => false,
'message' => $this->translator->trans($exception->getMessage(), array(), 'FOSUserBundle')
); // data to return via JSON
$response = new Response( json_encode( $result ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
} else {// if form login
// set authentication exception to session
$request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception);
return new RedirectResponse( $this->router->generate( 'fos_user_security_login' ) );
}
}
}
src/Moodio/Bundle/MainBundle/services.yml:
services:
moodio_main.security.authentication_handler:
class: Moodio\Bundle\UserBundle\Handler\AuthenticationHandler
public: false
arguments:
- @router
- @session
- @translator
- @form.csrf_provider
security.yml 防火墙:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
success_handler: moodio_main.security.authentication_handler
failure_handler: moodio_main.security.authentication_handler
logout: true
anonymous: true
我的javascript
$('#_submit').click(function(e){
e.preventDefault();
var frm = $('form');
$.ajax({
type : frm.attr('method'),
url : frm.attr('action'),
data : frm.serialize(),
success : function(data, status, object) {
if(data.error) $('.error').html(data.message);
},
error: function(data, status, object){
console.log(data.message);
}
});
});
我尝试了 this answer 中的一些答案,但它对我不起作用。我实际上不明白为什么它会有所作为,因为 FOSUserBundle 已经创建了 csrf-token 并使用 {{ csrf_token }}.
将其包含在 twig 模板中目前我正在使用标准的 FOSUserBundle 模板(并且只添加了 ajax 所需的 js 视图行)。
我还尝试过一件事,看看 csrf 验证是否有效,即在 onAuthenticationFailure 函数中生成 csrf 令牌,并在下一行检查它是否有效。在这种情况下,isCsrfTokenValid() 返回 true。
当我在防火墙中(在 security.yml 中)停用 csrf_provider 时,我总是收到消息 "Bad credentials",即使凭据是正确的。
如果您使用的是最新版本的 FOSUserBundle,则 csrf 提供程序已更改为 security.csrf.token_manager。您的表单可能正在使用 form.csrf_provider 生成令牌,而 FOSUB 可能正在使用另一个。或者:
- 将您的 FOSUserBundle 依赖项明确设置为 1.2 或 1.3,而不是 dev-master
- 手动将 csrf 提供程序设置为正确的服务。
无论哪种方式,请清除您的 cookie 并重新启动您的开发服务器以确保其中没有遗留信息。
我终于可以解决我的问题了:
我发现 Divi-AjaxLoginBundle 非常有用。我不确定问题出在哪里,因为我实际上有与此捆绑包相同的 AuthenticationHandlers,但 DependencyInjection 文件夹中也有一些文件可能完成了工作。
感谢所有帮助过我的人。