I have a server sided API developed with Symfony2 and now I try to authenticate.
- The Client / The Mobile Device App must authentificate with an API Key
- The User who uses the app must authentificate with Email + Password and gets an access_token
Therefore I use 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 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 in detail are:
- The Method
loadUserByUsername
needs to find the User entity by searching the Username. But from this Class I do not have access to database. I found examples using a static methodUser::find()
but there is not such a method and the Entity - the model of MVC- does also not have access to database. How do I get the User out of the database ? - I want to authentificate first the APP itself for general API access and second the User for personal information and limited editing rights. When the User logged in via Email and Password an the data was saved eg in UsernamePasswortToken how does the next call from the same Client can access data with the access_token. The session does not have effect on these AJAX HTTP Requests.