Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Token Persistence #11

Merged
merged 5 commits into from
Jun 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ require_once 'vendor/autoload.php';
//Create your auth strategy
$authStrategy = new QueryAuthStrategy(['username' => 'admin', 'password' => 'admin']);

//Optionnal: create your persistence strategy
$persistenceStrategy = null;

$baseUri = 'http://api.example.org/';

// Create authClient
Expand All @@ -42,6 +45,7 @@ $authClient = new Client(['base_uri' => $baseUri]);
$jwtManager = new JwtManager(
$authClient,
$authStrategy,
$persistenceStrategy,
[
'token_url' => '/api/token',
]
Expand Down Expand Up @@ -115,6 +119,102 @@ $authStrategy = new JsonAuthStrategy(
);
```

## Persistence

To avoid requesting a token everytime php runs, you can pass to `JwtManager` an implementation of `TokenPersistenceInterface`.
By default `NullTokenPersistence` will be used.

### Simpe cache adapter (PSR-16)

If you have any [PSR-16 compatible cache](https://www.php-fig.org/psr/psr-16/), you can use it as a persistence handler:

```php
<?php

use Eljam\GuzzleJwt\Persistence\SimpleCacheTokenPersistence;
use Psr\SimpleCache\CacheInterface;

/**
* @var CacheInterface
*/
$psr16cache;

$persistenceStrategy = new SimpleCacheTokenPersistence($psr16cache);
```

Optionnally you can specify the TTL and cache key used:

```php
<?php

use Eljam\GuzzleJwt\Persistence\SimpleCacheTokenPersistence;
use Psr\SimpleCache\CacheInterface;

/**
* @var CacheInterface
*/
$psr16cache;

$ttl = 1800;
$cacheKey = 'myUniqueKey';

$persistenceStrategy = new SimpleCacheTokenPersistence($psr16cache, $ttl, $cacheKey);
```


### Custom persistence

You may create you own persistence handler by implementing the `TokenPersistenceInterface`:

```php
namespace App\Jwt\Persistence;

use Eljam\GuzzleJwt\Persistence\TokenPersistenceInterface;

class MyCustomPersistence implements TokenPersistenceInterface
{
/**
* Save the token data.
*
* @param JwtToken $token
*/
public function saveToken(JwtToken $token)
{
// Use APCu, Redis or whatever fits your needs.
return;
}

/**
* Retrieve the token from storage and return it.
* Return null if nothing is stored.
*
* @return JwtToken Restored token
*/
public function restoreToken()
{
return null;
}

/**
* Delete the saved token data.
*/
public function deleteToken()
{
return;
}

/**
* Returns true if a token exists (although it may not be valid)
*
* @return bool
*/
public function hasToken()
{
return false;
}
}
```

## Token key

By default this library assumes your json response has a key `token`, something like this:
Expand All @@ -131,6 +231,7 @@ but now you can change the token_key in the JwtManager options:
$jwtManager = new JwtManager(
$authClient,
$authStrategy,
$persistenceStrategy,
[
'token_url' => '/api/token',
'token_key' => 'access_token',
Expand Down Expand Up @@ -165,6 +266,7 @@ Json example:
$jwtManager = new JwtManager(
$authClient,
$authStrategy,
$persistenceStrategy,
[
'token_url' => '/api/token',
'token_key' => 'access_token',
Expand Down
5 changes: 5 additions & 0 deletions Tests/Manager/JwtManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function (RequestInterface $request) {
$jwtManager = new JwtManager(
$authClient,
$authStrategy,
null,
['token_url' => '/api/token', 'timeout' => 3]
);
$token = $jwtManager->getJwtToken();
Expand Down Expand Up @@ -87,6 +88,7 @@ function (RequestInterface $request) {
$jwtManager = new JwtManager(
$authClient,
$authStrategy,
null,
['token_url' => '/api/token', 'timeout' => 3, 'token_key' => 'tokenkey']
);
$token = $jwtManager->getJwtToken();
Expand Down Expand Up @@ -141,6 +143,7 @@ function (RequestInterface $request) {
$jwtManager = new JwtManager(
$authClient,
$authStrategy,
null,
['token_url' => '/api/token', 'timeout' => 3]
);
$token = $jwtManager->getJwtToken();
Expand Down Expand Up @@ -200,6 +203,7 @@ function (RequestInterface $request) {
$jwtManager = new JwtManager(
$authClient,
$authStrategy,
null,
['token_url' => '/api/token', 'timeout' => 3]
);
$token = $jwtManager->getJwtToken();
Expand Down Expand Up @@ -263,6 +267,7 @@ function (RequestInterface $request) {
$jwtManager = new JwtManager(
$authClient,
$authStrategy,
null,
['token_url' => '/api/token', 'timeout' => 3]
);
$token = $jwtManager->getJwtToken();
Expand Down
48 changes: 48 additions & 0 deletions Tests/Persistence/TokenPersistenceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Eljam\GuzzleJwt\Tests\Persistence;

use Eljam\GuzzleJwt\JwtToken;
use Eljam\GuzzleJwt\Persistence\NullTokenPersistence;
use Eljam\GuzzleJwt\Persistence\SimpleCacheTokenPersistence;
use Symfony\Component\Cache\Simple\FilesystemCache;

/**
* @author Nicolas Reynis (nreynis)
*/
class TokenPersistenceTest extends \PHPUnit_Framework_TestCase
{
/**
* testNullTokenPersistence.
*/
public function testNullTokenPersistence()
{
$tokenPersistence = new NullTokenPersistence();
$token = new JwtToken('foo', new \DateTime('now'));

$tokenPersistence->saveToken($token);

$this->assertFalse($tokenPersistence->hasToken());
$this->assertNull($tokenPersistence->restoreToken());
}

/**
* testSimpleCacheTokenPersistence.
*/
public function testSimpleCacheTokenPersistence()
{
$simpleCache = new FilesystemCache();
$tokenPersistence = new SimpleCacheTokenPersistence($simpleCache);
$token = new JwtToken('foo', new \DateTime('now'));

$tokenPersistence->saveToken($token);

$this->assertTrue($tokenPersistence->hasToken());
$this->assertEquals($tokenPersistence->restoreToken()->getToken(), $token->getToken());

$tokenPersistence->deleteToken();

$this->assertFalse($tokenPersistence->hasToken());
$this->assertNull($tokenPersistence->restoreToken());
}
}
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
},
"require-dev": {
"phpunit/phpunit": "4.5",
"satooshi/php-coveralls": "^0.6.1"
"satooshi/php-coveralls": "^0.6.1",
"symfony/cache": ">=3.3"
},
"require": {
"php" : ">=5.5.0",
"guzzlehttp/guzzle": "~6.0",
"psr/simple-cache": "^1.0",
"symfony/options-resolver": ">=2.8"
},
"config": {
Expand Down
28 changes: 25 additions & 3 deletions src/Manager/JwtManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Eljam\GuzzleJwt\Manager;

use Eljam\GuzzleJwt\JwtToken;
use Eljam\GuzzleJwt\Persistence\NullTokenPersistence;
use Eljam\GuzzleJwt\Persistence\TokenPersistenceInterface;
use Eljam\GuzzleJwt\Strategy\Auth\AuthStrategyInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\request;
Expand Down Expand Up @@ -41,21 +43,33 @@ class JwtManager
*/
protected $token;

/**
* @var TokenPersistenceInterface
*/
protected $tokenPersistence;

/**
* Constructor.
*
* @param ClientInterface $client
* @param AuthStrategyInterface $auth
* @param array $options
* @param ClientInterface $client
* @param AuthStrategyInterface $auth
* @param TokenPersistenceInterface $tokenPersistence
* @param array $options
*/
public function __construct(
ClientInterface $client,
AuthStrategyInterface $auth,
TokenPersistenceInterface $tokenPersistence = null,
array $options = []
) {
$this->client = $client;
$this->auth = $auth;

if ($tokenPersistence === null) {
$tokenPersistence = new NullTokenPersistence();
}
$this->tokenPersistence = $tokenPersistence;

$resolver = new OptionsResolver();
$resolver->setDefaults([
'token_url' => '/token',
Expand All @@ -76,10 +90,17 @@ public function __construct(
*/
public function getJwtToken()
{
// If token is not set try to get it from the persistent storage.
if ($this->token === null) {
$this->token = $this->tokenPersistence->restoreToken();
}

if ($this->token && $this->token->isValid()) {
return $this->token;
}

$this->tokenPersistence->deleteToken();

$url = $this->options['token_url'];

$requestOptions = array_merge(
Expand All @@ -106,6 +127,7 @@ public function getJwtToken()
}

$this->token = new JwtToken($body[$this->options['token_key']], $expiration);
$this->tokenPersistence->saveToken($this->token);

return $this->token;
}
Expand Down
31 changes: 31 additions & 0 deletions src/Persistence/NullTokenPersistence.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Eljam\GuzzleJwt\Persistence;

use Eljam\GuzzleJwt\JwtToken;

/**
* @author Sevastian Hübner <development@tryfailrepeat.de>
*/
class NullTokenPersistence implements TokenPersistenceInterface
{
public function saveToken(JwtToken $token)
{
return;
}

public function restoreToken()
{
return null;
}

public function deleteToken()
{
return;
}

public function hasToken()
{
return false;
}
}
Loading