Skip to content

Commit a25afb2

Browse files
committed
feature: implement caching for jwks and user data
1 parent d55d796 commit a25afb2

File tree

1 file changed

+47
-34
lines changed

1 file changed

+47
-34
lines changed

src/Client.php

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
66
use Firebase\JWT\ExpiredException;
77
use Firebase\JWT\JWT;
88
use Firebase\JWT\JWK;
9+
910
use Symfony\Component\HttpClient\HttpClient;
11+
use Symfony\Contracts\HttpClient\HttpClientInterface;
1012
use Symfony\Component\HttpClient\RetryableHttpClient;
13+
use Phpfastcache\CacheManager;
14+
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
15+
use Phpfastcache\Config\ConfigurationOption;
1116

1217
use TRSTD\COT\Logger;
1318
use TRSTD\COT\AuthStorage;
@@ -27,6 +32,10 @@
2732
define('RESOURCE_SERVER_BASE_URI', 'https://scoped-cns-data.consumer-account-test.trustedshops.com/api/v1/');
2833
}
2934

35+
CacheManager::setDefaultConfig(new ConfigurationOption([
36+
"path" => __DIR__ . "/cache"
37+
]));
38+
3039
class Client
3140
{
3241
private static $identityCookie = 'TRSTD_ID_TOKEN';
@@ -59,23 +68,28 @@ class Client
5968
private $logger;
6069

6170
/**
62-
* @var RetryableHttpClient
71+
* @var HttpClientInterface
6372
*/
6473
private $authHttpClient;
6574

6675
/**
67-
* @var RetryableHttpClient
76+
* @var HttpClientInterface
6877
*/
6978
private $resourceHttpClient;
7079

80+
/**
81+
* @var ExtendedCacheItemPoolInterface
82+
*/
83+
private $cacheItemPool;
84+
7185
/**
7286
* @param string $tsId TS ID
7387
* @param string $clientId client ID
7488
* @param string $clientSecret client secret
7589
* @param AuthStorage $authStorage auth storage instance
7690
* @throws RequiredParameterMissingException if any required parameter is missing
7791
*/
78-
public function __construct($tsId, $clientId, $clientSecret, $authStorage)
92+
public function __construct($tsId, $clientId, $clientSecret, AuthStorage $authStorage)
7993
{
8094
if (!$tsId) {
8195
throw new RequiredParameterMissingException('TS ID is required.');
@@ -99,13 +113,10 @@ public function __construct($tsId, $clientId, $clientSecret, $authStorage)
99113
$this->authStorage = $authStorage;
100114
$this->logger = new Logger();
101115

102-
$this->authHttpClient = new RetryableHttpClient(HttpClient::create()->withOptions([
103-
'base_uri' => AUTH_SERVER_BASE_URI,
104-
]));
116+
$this->authHttpClient = HttpClient::createForBaseUri(AUTH_SERVER_BASE_URI);
117+
$this->resourceHttpClient = HttpClient::createForBaseUri(RESOURCE_SERVER_BASE_URI);
105118

106-
$this->resourceHttpClient = new RetryableHttpClient(HttpClient::create()->withOptions([
107-
'base_uri' => RESOURCE_SERVER_BASE_URI,
108-
]));
119+
$this->cacheItemPool = CacheManager::getInstance('files');
109120
}
110121

111122
/**
@@ -136,18 +147,22 @@ public function getConnectedConsumerAnonymousData()
136147
return null;
137148
}
138149

150+
$cachedConsumerAnonymousDataItem = $this->cacheItemPool->getItem('consumer_anonymous_data');
151+
if ($cachedConsumerAnonymousDataItem->isHit()) {
152+
return $cachedConsumerAnonymousDataItem->get();
153+
}
154+
139155
$headers = [
140156
'Content-Type: application/json',
141157
'Authorization: Bearer ' . $accessToken,
142158
];
143159

144160
$response = $this->resourceHttpClient->request("GET", "anonymous-data" . ($this->tsId ? "?shopId=" . $this->tsId : ""), ['headers' => $headers]);
161+
$consumerAnonymousData = json_decode($response->getContent());
162+
$cachedConsumerAnonymousDataItem->set($consumerAnonymousData)->expiresAfter(5);
163+
$this->cacheItemPool->save($cachedConsumerAnonymousDataItem);
145164

146-
if (200 !== $response->getStatusCode()) {
147-
return null;
148-
}
149-
150-
return json_decode($response->getContent());
165+
return $consumerAnonymousData;
151166
} catch (Exception $ex) {
152167
$this->logger->error($ex->getMessage());
153168
return null;
@@ -177,14 +192,14 @@ private function disconnect()
177192
{
178193
if (isset($_COOKIE[self::$identityCookie])) {
179194
$idToken = $_COOKIE[self::$identityCookie];
180-
$decodedToken = $this->decodeToken($idToken);
195+
$decodedToken = $this->decodeToken($idToken, false);
181196
$this->authStorage->remove($decodedToken->ctc_id);
182197
$this->removeIdentityCookie();
183198
}
184199
}
185200

186201
/**
187-
* @param string $codecode to get token
202+
* @param string $code code to get token
188203
* @return Token|null
189204
*/
190205
private function getToken($code)
@@ -203,11 +218,6 @@ private function getToken($code)
203218
];
204219

205220
$response = $this->authHttpClient->request("POST", "token", ['headers' => $headers, 'body' => $data]);
206-
207-
if (201 !== $response->getStatusCode()) {
208-
return null;
209-
}
210-
211221
$responseJson = json_decode($response->getContent());
212222
if (!$responseJson || isset($responseJson->error)) {
213223
return null;
@@ -234,11 +244,6 @@ private function getRefreshedToken($refreshToken)
234244
];
235245

236246
$response = $this->authHttpClient->request("POST", "token", ['headers' => $headers, 'body' => $data]);
237-
238-
if (201 !== $response->getStatusCode()) {
239-
return null;
240-
}
241-
242247
$responseJson = json_decode($response->getContent());
243248
if (!$responseJson || isset($responseJson->error)) {
244249
return null;
@@ -302,7 +307,7 @@ private function getOrRefreshAccessToken($idToken)
302307
private function setTokenOnStorage(Token $token)
303308
{
304309
try {
305-
$decodedToken = $this->decodeToken($token->idToken);
310+
$decodedToken = $this->decodeToken($token->idToken, false);
306311
$this->authStorage->set($token, $decodedToken->ctc_id);
307312
} catch (ExpiredException $ex) {
308313
$this->logger->debug('id token is expired. returning...');
@@ -319,7 +324,7 @@ private function setTokenOnStorage(Token $token)
319324
private function getTokenFromStorage($idToken)
320325
{
321326
try {
322-
$decodedToken = $this->decodeToken($idToken);
327+
$decodedToken = $this->decodeToken($idToken, false);
323328
return $this->authStorage->getByCtcId($decodedToken->ctc_id);
324329
} catch (ExpiredException $ex) {
325330
$this->logger->debug('id token is expired. returning...');
@@ -331,9 +336,14 @@ private function getTokenFromStorage($idToken)
331336
return null;
332337
}
333338

334-
private function decodeToken($token)
339+
private function decodeToken($token, $validateExp = true)
335340
{
336341
try {
342+
if (!$validateExp) {
343+
$tks = explode('.', $token);
344+
return JWT::jsonDecode(JWT::urlsafeB64Decode($tks[1]));
345+
}
346+
337347
return JWT::decode($token, $this->getJWKS());
338348
} catch (Exception $ex) {
339349
$this->logger->error($ex->getMessage());
@@ -343,15 +353,18 @@ private function decodeToken($token)
343353

344354
private function getJWKS()
345355
{
346-
$response = $this->authHttpClient->request("GET", "certs");
356+
$cachedJWKSItem = $this->cacheItemPool->getItem('jwks');
347357

348-
if (200 !== $response->getStatusCode()) {
349-
return null;
358+
if (!$cachedJWKSItem->isHit()) {
359+
$response = $this->authHttpClient->request("GET", "certs");
360+
$jwks = json_decode($response->getContent(), true);
361+
$this->cacheItemPool->getItem('jwks')->set($jwks)->expiresAfter(3600);
362+
$this->cacheItemPool->save($cachedJWKSItem);
350363
}
351364

352-
$responseJson = json_decode($response->getContent());
365+
$jwks = $cachedJWKSItem->get();
353366

354-
return JWK::parseKeySet($responseJson->keys);
367+
return JWK::parseKeySet($jwks);
355368
}
356369

357370
/**

0 commit comments

Comments
 (0)