diff --git a/cookbook/security/api_key_authentication.rst b/cookbook/security/api_key_authentication.rst index 745a5792830..a33e30449f9 100644 --- a/cookbook/security/api_key_authentication.rst +++ b/cookbook/security/api_key_authentication.rst @@ -41,7 +41,7 @@ value and then a User object is created:: // $apiKey = $request->headers->get('apikey'); if (!$apiKey) { - throw new BadCredentialsException('No API key found'); + throw new BadCredentialsException(); // or to just skip api key authentication // return null; @@ -54,6 +54,11 @@ value and then a User object is created:: ); } + public function supportsToken(TokenInterface $token, $providerKey) + { + return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey; + } + public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) { if (!$userProvider instanceof ApiKeyUserProvider) { @@ -83,16 +88,11 @@ value and then a User object is created:: $user->getRoles() ); } - - public function supportsToken(TokenInterface $token, $providerKey) - { - return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey; - } } Once you've :ref:`configured ` everything, you'll be able to authenticate by adding an apikey parameter to the query -string, like ``http://example.com/admin/foo?apikey=37b51d194a7513e45b56f6524f2d51f2``. +string, like ``http://example.com/api/foo?apikey=37b51d194a7513e45b56f6524f2d51f2``. The authentication process has several steps, and your implementation will probably differ: @@ -177,7 +177,7 @@ The ``$userProvider`` might look something like this:: null, // the roles for the user - you may choose to determine // these dynamically somehow based on the user - array('ROLE_USER') + array('ROLE_API') ); } @@ -249,6 +249,7 @@ would allow you to have custom data on the ``User`` object. Finally, just make sure that ``supportsClass()`` returns ``true`` for User objects with the same class as whatever user you return in ``loadUserByUsername()``. + If your authentication is stateless like in this example (i.e. you expect the user to send the API key with every request and so you don't save the login to the session), then you can simply throw the ``UnsupportedUserException`` @@ -262,7 +263,7 @@ exception in ``refreshUser()``. Handling Authentication Failure ------------------------------- -In order for your ``ApiKeyAuthenticator`` to correctly display a 403 +In order for your ``ApiKeyAuthenticator`` to correctly display a 401 http status when either bad credentials or authentication fails you will need to implement the :class:`Symfony\\Component\\Security\\Http\\Authentication\\AuthenticationFailureHandlerInterface` on your Authenticator. This will provide a method ``onAuthenticationFailure`` which @@ -285,7 +286,7 @@ you can use to create an error ``Response``. public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { - return new Response("Authentication Failed.", 403); + return new Response("Authentication Failed.", 401); } } @@ -353,7 +354,7 @@ using the ``simple_preauth`` and ``provider`` keys respectively: firewalls: secured_area: - pattern: ^/admin + pattern: ^/api stateless: true simple_preauth: authenticator: apikey_authenticator @@ -376,7 +377,7 @@ using the ``simple_preauth`` and ``provider`` keys respectively: @@ -396,7 +397,7 @@ using the ``simple_preauth`` and ``provider`` keys respectively: $container->loadFromExtension('security', array( 'firewalls' => array( 'secured_area' => array( - 'pattern' => '^/admin', + 'pattern' => '^/api', 'stateless' => true, 'simple_preauth' => array( 'authenticator' => 'apikey_authenticator', @@ -411,6 +412,44 @@ using the ``simple_preauth`` and ``provider`` keys respectively: ), )); +If you have defined ``access_control``, make sure to add a new entry: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/security.yml + security: + # ... + + access_control: + - { path: ^/api, roles: ROLE_API } + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // app/config/security.php + $container->loadFromExtension('security', array( + 'access_control' => array( + array( + 'path' => '^/api', + 'role' => 'ROLE_API', + ), + ), + )); + That's it! Now, your ``ApiKeyAuthenticator`` should be called at the beginning of each request and your authentication process will take place. @@ -443,7 +482,7 @@ configuration or set it to ``false``: firewalls: secured_area: - pattern: ^/admin + pattern: ^/api stateless: false simple_preauth: authenticator: apikey_authenticator @@ -466,7 +505,7 @@ configuration or set it to ``false``: @@ -485,7 +524,7 @@ configuration or set it to ``false``: $container->loadFromExtension('security', array( 'firewalls' => array( 'secured_area' => array( - 'pattern' => '^/admin', + 'pattern' => '^/api', 'stateless' => false, 'simple_preauth' => array( 'authenticator' => 'apikey_authenticator',