User and API authentication via token / key

I have a server-side API developed with Symfony2 and am now trying to authenticate.

  • Mobile client / app must authenticate with API key
  • The user who is using the app must authenticate with Email + Password and receive an access_token

So I am using this firewall and apikey authenticator

firewalls:
    login:
        pattern:  ^/login$
        security: false

    secured_area:
        pattern: ^/
        stateless: true
        simple_preauth:
            authenticator: apikey_authenticator

      

Api Key Authenticator

namespace Rental\APIBundle\Security;

use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;


class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface    {
    protected $userProvider;

    public function __construct(ApiKeyUserProvider $userProvider)
    {
        $this->userProvider = $userProvider;
    }

    public function createToken(Request $request, $providerKey)
    {

        //$apiKey = $request->query->get('apikey');
        // use test value
        $apiKey = "234234234";

        if (!$apiKey) {
            throw new BadCredentialsException('No API key found');
        }

        return new PreAuthenticatedToken(
            'anon.',
            $apiKey,
            $providerKey
        );
    }

    public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
    {
        $apiKey = $token->getCredentials();
        $username = $this->userProvider->getUsernameForApiKey($apiKey);

        if (!$username) {
            throw new AuthenticationException(
                sprintf('API Key "%s" does not exist.', $apiKey)
            );
        }

        $user = $this->userProvider->loadUserByUsername($username);

        return new PreAuthenticatedToken(
            $user,
            $apiKey,
            $providerKey,
            $user->getRoles()
        );
    }

    public function supportsToken(TokenInterface $token, $providerKey)
    {
        return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
    }
}

      

Up to this point, no problem. Now this class uses the methods of the following class

namespace Rental\APIBundle\Security;

use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\User;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;

class ApiKeyUserProvider implements UserProviderInterface {
    public function getUsernameForApiKey($apiKey)
    {
        // Look up the username based on the token in the database
        // use test value
        $username = "Alex";

        return $username;
    }

    public function loadUserByUsername($username)
    {
        // return User by Username
    }

    public function refreshUser(UserInterface $user)
    {
        // code
    }

    public function supportsClass($class)
    {
        return 'Symfony\Component\Security\Core\User\User' === $class;
    }
}

      

My problems are in detail:

  • The method loadUserByUsername

    should find the user object by looking up the username. But from this class, I do not have access to the database. I found examples using a static method User::find()

    , but there is no such method and the Entity - the MVC model - also has no database access. How do I get a user from the database?
  • I want to authenticate the APP first for API sharing and second for personal information and limited editing rights. When the user logged in via email and password, the data was stored, for example, in UsernamePasswortToken, how the next call from the same client can access the data using the access_token. The session does not affect these HTTP AJAX requests.
+3


source to share


1 answer


1. To do this, you have to use Dependency Injection and inject an object manager in your provider.

 your_api_key_user_provider:
            class:     Rental\APIBundle\Security\ApiKeyUserProvider
            arguments: ["@doctrine.orm.entity_manager"]
 apikey_authenticator:
            class:     Rental\APIBundle\Security\ApiKeyAuthenticator
            arguments: [""@your_api_key_user_provider"]  

      

After that add it to the provider:



    use Doctrine\ORM\EntityManager;

    class ApiKeyUserProvider implements UserProviderInterface {

        protected $em;

        public function __construct(EntityManager $em){
            $this->em = $entityManager;
        }
       //... Now you have access to database

    }

      

2. Ajax can send cookies and php can handle requests like normal and session. Make sure your request is sending cookies (see Why is jQuery's jQuery method not sending my session cookie?

+2


source







All Articles