This repository has been archived by the owner on Jul 4, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 719
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #1296 Add support for the Guard component to the SecurityServ…
…iceProvider (GromNaN) This PR was squashed before being merged into the 2.0.x-dev branch (closes #1296). Discussion ---------- Add support for the Guard component to the SecurityServiceProvider | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #1260 | License | MIT | Doc PR | included Services configuration are extracted from the SecurityBundle [`guard.xml`](https://github.com/symfony/symfony/blob/3.0/src/Symfony/Bundle/SecurityBundle/Resources/config/guard.xml) and [`GuardAuthenticationFactory`](https://github.com/symfony/symfony/blob/3.0/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php) Usage is quite simple, the `guard` type can be configured in the firewall like other ones. ```php $app['app.authenticator'] = function ($app) { return new Authenticator(); }; $app->register(new Silex\Provider\SecurityServiceProvider(), [ 'security.firewalls' => [ 'main' => [ 'pattern' => '^/admin', 'guard' => [ 'authenticators' => [ 'app.authenticator' ] ] ] ] ]); ``` Commits ------- 4b5ccc9 Add support for the Guard component to the SecurityServiceProvider
- Loading branch information
Showing
5 changed files
with
400 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
How to Create a Custom Authentication System with Guard | ||
======================================================= | ||
|
||
Whether you need to build a traditional login form, an API token | ||
authentication system or you need to integrate with some proprietary | ||
single-sign-on system, the Guard component can make it easy... and fun! | ||
|
||
In this example, you'll build an API token authentication system and | ||
learn how to work with Guard. | ||
|
||
Step 1) Create the Authenticator Class | ||
-------------------------------------- | ||
|
||
Suppose you have an API where your clients will send an X-AUTH-TOKEN | ||
header on each request. This token is composed of the username followed | ||
by a password, separated by a colon (e.g. ``X-AUTH-TOKEN: coolguy:awesomepassword``). | ||
Your job is to read this, find theassociated user (if any) and check | ||
the password. | ||
|
||
To create a custom authentication system, just create a class and make | ||
it implement GuardAuthenticatorInterface. Or, extend the simpler | ||
AbstractGuardAuthenticator. This requires you to implement six methods: | ||
|
||
.. code-block:: php | ||
<?php | ||
namespace App\Security; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpFoundation\JsonResponse; | ||
use Symfony\Component\Security\Core\User\UserInterface; | ||
use Symfony\Component\Security\Core\User\UserProviderInterface; | ||
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; | ||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||
use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
class TokenAuthenticator extends AbstractGuardAuthenticator | ||
{ | ||
private $encoderFactory; | ||
public function __construct(EncoderFactoryInterface $encoderFactory) | ||
{ | ||
$this->encoderFactory = $encoderFactory; | ||
} | ||
public function getCredentials(Request $request) | ||
{ | ||
// Checks if the credential header is provided | ||
if (!$token = $request->headers->get('X-AUTH-TOKEN')) { | ||
return; | ||
} | ||
// Parse the header or ignore it if the format is incorrect. | ||
if (false === strpos(':', $token)) { | ||
return; | ||
} | ||
list($username, $secret) = explode(':', $token, 2); | ||
return array( | ||
'username' => $username, | ||
'secret' => $secret, | ||
); | ||
} | ||
public function getUser($credentials, UserProviderInterface $userProvider) | ||
{ | ||
return $userProvider->loadUserByUsername($credentials['username']); | ||
} | ||
public function checkCredentials($credentials, UserInterface $user) | ||
{ | ||
// check credentials - e.g. make sure the password is valid | ||
// return true to cause authentication success | ||
$encoder = $this->encoderFactory->getEncoder($user); | ||
return $encoder->isPasswordValid( | ||
$user->getPassword(), | ||
$credentials['secret'], | ||
$user->getSalt() | ||
); | ||
} | ||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) | ||
{ | ||
// on success, let the request continue | ||
return; | ||
} | ||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) | ||
{ | ||
$data = array( | ||
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()), | ||
// or to translate this message | ||
// $this->translator->trans($exception->getMessageKey(), $exception->getMessageData()) | ||
); | ||
return new JsonResponse($data, 403); | ||
} | ||
/** | ||
* Called when authentication is needed, but it's not sent | ||
*/ | ||
public function start(Request $request, AuthenticationException $authException = null) | ||
{ | ||
$data = array( | ||
// you might translate this message | ||
'message' => 'Authentication Required', | ||
); | ||
return new JsonResponse($data, 401); | ||
} | ||
public function supportsRememberMe() | ||
{ | ||
return false; | ||
} | ||
} | ||
Step 2) Configure the Authenticator | ||
----------------------------------- | ||
|
||
To finish this, register the class as a service: | ||
|
||
.. code-block:: php | ||
$app['app.token_authenticator'] = function ($app) { | ||
return new App\Security\TokenAuthenticator($app['security.encoder_factory']); | ||
}; | ||
Finally, configure your `security.firewalls` key to use this authenticator: | ||
|
||
.. code-block:: php | ||
$app['security.firewalls'] => array( | ||
'main' => array( | ||
'guard' => array( | ||
'authenticators' => array( | ||
'app.token_authenticator' | ||
), | ||
// Using more than 1 authenticator, you must specify | ||
// which one is used as entry point. | ||
// 'entry_point' => 'app.token_authenticator', | ||
), | ||
// configure where your users come from. Hardcode them, or load them from somewhere | ||
// http://silex.sensiolabs.org/doc/providers/security.html#defining-a-custom-user-provider | ||
'users' => array( | ||
'victoria' => array('ROLE_USER', 'randomsecret'), | ||
), | ||
// 'anonymous' => true | ||
), | ||
); | ||
.. note:: | ||
You can use many authenticators, they are executed by the order | ||
they are configured. | ||
|
||
You did it! You now have a fully-working API token authentication | ||
system. If your homepage required ROLE_USER, then you could test it | ||
under different conditions: | ||
|
||
.. code-block:: bash | ||
# test with no token | ||
curl http://localhost:8000/ | ||
# {"message":"Authentication Required"} | ||
# test with a bad token | ||
curl -H "X-AUTH-TOKEN: alan" http://localhost:8000/ | ||
# {"message":"Username could not be found."} | ||
# test with a working token | ||
curl -H "X-AUTH-TOKEN: victoria:ransomsecret" http://localhost:8000/ | ||
# the homepage controller is executed: the page loads normally | ||
For more details read the Symfony cookbook entry on | ||
`How to Create aCustom Authentication System with Guard <http://symfony.com/doc/current/cookbook/security/guard-authentication.html>`_. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.