Symfony2 : AJAX request : How to handle authentication when needed?
Here is a solution (see here for details) :
Security :
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 :
services:
fbn_user.login_entry_point:
class: FBN\UserBundle\EventListener\LoginEntryPoint
arguments: [ @router ]
Service class :
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);
}
},
});
});
});
Symfony2 AJAX Login
David's answer is good, but it's lacking a little detail for newbs - so this is to fill in the blanks.
In addition to creating the AuthenticationHandler you'll need to set it up as a service using the service configuration in the bundle where you created the handler. The default bundle generation creates an xml file, but I prefer yml. Here's an example services.yml file:
#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' }
You'd need to modify the DependencyInjection bundle extension to use yml instead of xml like so:
#src/Vendor/BundleName/DependencyInjection/BundleExtension.php
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
Then in your app's security configuration you set up the references to the authentication_handler service you just defined:
# 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
Symfony2 Login redirect after ajax request
You can force your security to always redirect to target path instead of checking referer:
firewalls:
secured_area:
form_login:
always_use_default_target_path: true
default_target_path: /userProfilePage
P.S. You should read documentation better
How to login using ajax in Symfony 2?
I made it work by creating a LoginListener
PS: If someone wants to explain how to do that, I will mark that as the correct answer.
What’s the proper way to handle an AJAX call behind Symfony 4 firewall?
Your controller method redirects the Ajax call to the login page, because your JS doesn't send credentials (read: cookies).
If you're using fetch, use credentials
:
fetch(url, {
credentials: "same-origin"
}).then(...).catch(...);
See https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
If you're using another way to create the Ajax call, please update your question with some JS code and let me know :).
If you don't want to redirect the user to the login page when executing an XMLHttpRequest ('ajax'), use this listener to send a 403 response instead:
class AjaxAuthenticationListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::EXCEPTION => [
['onCoreException', 10],
],
];
}
public function onCoreException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
$request = $event->getRequest();
if (! $request->isXmlHttpRequest()) {
return;
}
if (! ($exception instanceof AuthenticationException) && ! ($exception instanceof AccessDeniedException)) {
return;
}
$event->setResponse(new Response('No access', 403));
}
}
Related Topics
Warning: Imagejpeg() [Function:Imagejpeg]: Gd-Jpeg: Jpeg Library Reports Unrecoverable Error
PHP Simplexml Namespace Problem
How to Catch a "Catchable Fatal Error" on PHP Type Hinting
Calculating Distance Between Zip Codes in PHP
Configure Multiple Databases in Zf2
Failed to Open Stream: Http Wrapper Does Not Support Writeable Connections
PHP Pdo::Bindparam() Data Types.. How Does It Work
Trim Unicode Whitespace in PHP 5.2
Getting All Dates for Mondays and Tuesdays for the Next Year
How to Get Int Instead String from Form
Laravel 4 - Logging SQL Queries
Encrypt Files Using Pgp in PHP