Login Symfony2 AJAX
Mam przykład, gdzie próbuję utworzyć login AJAX przy użyciu Symfony2 i FOSUserBundle. Ustawiam własne success_handler
i failure_handler
Pod form_login
w moim pliku security.yml
.
Oto Klasa:
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;
}
}
}
To działa świetnie do obsługi zarówno udanych, jak i nieudanych prób logowania AJAX. Jednak po włączeniu-nie jestem w stanie zalogować się za pomocą standardowej metody POST (non-AJAX). Otrzymuję następujący błąd:
Catchable Fatal Error: Argument 1 passed to Symfony\Component\HttpKernel\Event\GetResponseEvent::setResponse() must be an instance of Symfony\Component\HttpFoundation\Response, null given
Chciałbym, aby moje onAuthenticationSuccess
i onAuthenticationFailure
były tylko wykonywany dla XmlHttpRequests (żądań AJAX) i po prostu przekazuje wykonanie z powrotem do oryginalnego programu obsługi, jeśli nie.
TL; DR I want AJAX requested login attempts to return a JSON response for success and failure but I want it to not affected standard login via form POST.
7 answers
Odpowiedź Davida jest dobra, ale brakuje w niej trochę szczegółów dla newbsa - więc to ma wypełnić puste pola.
Oprócz tworzenia programu AuthenticationHandler musisz skonfigurować go jako usługę, korzystając z konfiguracji usługi w pakiecie, w którym został utworzony program obsługi. Domyślne generowanie pakietu tworzy plik xml, ale wolę yml. Oto przykładowe usługi.plik 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' }
Musisz zmodyfikować rozszerzenie pakietu DependencyInjection, aby używać yml zamiast xml jak tak:
#src/Vendor/BundleName/DependencyInjection/BundleExtension.php
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
Następnie w konfiguracji zabezpieczeń aplikacji skonfigurujesz odniesienia do usługi authentication_handler, którą właśnie zdefiniowałeś:
# 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:23
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);
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-28 09:23:23
Jeśli chcesz obsługiwać błąd formularza Fos UserBundle, musisz użyć:
$request->getSession()->set(SecurityContext::AUTHENTICATION_ERROR, $exception);
Zamiast:
$request->getSession()->setFlash('error', $exception->getMessage());
W pierwszej odpowiedzi.
(oczywiście pamiętaj o nagłówku: use Symfony \ Component \ Security \ Core\SecurityContext;)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-06 22:35:32
Załatwiłem to całkowicie za pomocą javascript:
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;
});
}
Oto Klasa AjaxFormDialog. Niestety nie przeportowałem go do wtyczki jQuery... https://gist.github.com/1601803
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-23 14:14:13
Musisz zwrócić obiekt odpowiedzi w obu przypadkach(Ajax lub nie). Dodaj 'else' i możesz zaczynać.
Domyślna implementacja to:
$response = $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request));
W AbstractAuthenticationListener::onSuccess
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-23 06:05:01
Zrobiłem mały pakiet dla nowych użytkowników, aby dostarczyć formularz logowania AJAX: https://github.com/Divi/AjaxLoginBundle
Wystarczy zamienić na form_login uwierzytelnienie przez ajax_form_login w zabezpieczeniu .yml .
Zachęcamy do zaproponowania nowej funkcji w Github issue tracker !
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-28 21:00:38
To może nie jest to, o co prosiło OP, ale natknąłem się na to pytanie i pomyślałem, że inni mogą mieć ten sam problem, co ja.
Dla tych, którzy implementują logowanie AJAX przy użyciu metody opisanej w zaakceptowanej odpowiedzi i którzy również używają AngularJS do wykonania żądania AJAX, to nie będzie działać domyślnie. $http
Angular nie ustawia nagłówków używanych przez Symfony podczas wywoływania metody $request->isXmlHttpRequest()
. Aby skorzystać z tej metody, należy ustawić odpowiednie nagłówek w żądaniu kątowym. To jest to, co zrobiłem, aby obejść problem:
$http({
method : 'POST',
url : {{ path('login_check') }},
data : data,
headers: {'X-Requested-With': 'XMLHttpRequest'}
})
Zanim użyjesz tej metody, pamiętaj, że nagłówek nie działa dobrze z CORS. Zobacz to pytanie
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:23