I'm making REST API for my JS driven app.
During login, the login form is submitted via AJAX to url /rest/login
of my API.
While I have separated firewalls for the API and the app itself, they share the same context which should mean, that when user authenticates against the API, he's authenticated against the app too. So, when the server returns 204, page will reload and it should redirect user to the app, because he's now logged in.
I tried to use pre-made check_login
page of the FOSUserBundle and pointed /rest/login
there.
login:
path: /rest/login
defaults:
_controller: FOSUserBundle:Security:check
methods: [ POST ]
That doesn't work, because it always returns redirect, no matter what. I read documentation for symfony and couldn't find, how to make a custom check_login
page. What I need is something like this
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use FOS\RestBundle\Controller\Annotations\View;
class SecurityController {
/**
* @View(statusCode=204)
*/
public function loginAction($username, $password) {
/* first I need to somehow authenticate user
using normal authentication, that I've set up */
...
/* Then I need to return 204 or throw exception,
based on result.
This is done using FOSRestBundle and it's
listeners. */
if(!$succesful) {
throw new AuthenticationException();
}
}
}
I don't have a clue how to do that. Nothing I found in any documentation helped me a bit. I will be thankful for any suggestion that would point me in right direction.
EDIT: To further simplify, what I'm aiming for. I want my login to function exactly the same as normal form_login. I only want to change the response, that it sends back - instead of redirect I want 204 on success and 401 on failure.
I was able to find a simple solution. I only needed to write a class, that implements AuthenticationSuccessHandlerInterface
and AuthenticationFailureHandlerInterface
.
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
class AuthenticationRestHandler implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface {
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) {
return new Response('', Response::HTTP_UNAUTHORIZED);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token) {
return new Response('', Response::HTTP_NO_CONTENT);
}
}
Then I registered it as a service and configured as handlers for the firewall.
services:
security.authentication_rest_handler:
class: AuthenticationRestHandler
security:
firewalls:
rest:
pattern: ^rest
context: app
form_login:
check_path: /rest/login
provider: fos_userbundle
failure_handler: inspireon.security.authentication_rest_handler
success_handler: inspireon.security.authentication_rest_handler
username_parameter: login
password_parameter: password
Problem solved and no complicated authentication provider needed :-)