Symfony2 App with RESTful authentication, using FOSRestBundle and FOSUserBundle

13,511

Solution 1

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 :-)

Solution 2

I understood your problem because I passed by a similar situation but with SOAP services. In the middle I could re-search the security wsse and Symfony2 has already provides a solution

http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html

It works with a real token and you can match with an user in FOSUserBundle. The only think that I see is the field "password" that you want to compare is the same that in the database (with encryption) then I decided to create a extra field only for this use.

I hope that it help you.

Greetings

Share:
13,511

Related videos on Youtube

Michal Artazov
Author by

Michal Artazov

Senior software developer at SignageOS.io Expert on everything web related but I prefer backend

Updated on June 04, 2022

Comments

  • Michal Artazov
    Michal Artazov almost 2 years

    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.

    • If the login is succesful, it returns 204
    • If it fails, it returns 401

    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.

  • Michal Artazov
    Michal Artazov over 9 years
    So, do I need to implement whole new custom authentication provider? Imo it's a bit overkill, because all I need to change is the behaviour of the listener to send 204/401 instead of redirect, not the whole process.