Skip to content

Commit

Permalink
Token Persistence (#11)
Browse files Browse the repository at this point in the history
TokenPersistence with PSR-16 cache adapter
  • Loading branch information
nreynis authored and eljam committed Jun 12, 2019
1 parent 49a7fe8 commit 07d1f70
Show file tree
Hide file tree
Showing 8 changed files with 326 additions and 4 deletions.
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 <[email protected]>
*/
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

0 comments on commit 07d1f70

Please sign in to comment.