Skip to content

Commit fab8f40

Browse files
authored
Merge pull request #19 from duronrulez/feature/oauth2
Add basic oAuth2 support
2 parents 9d7c7bd + 924e303 commit fab8f40

File tree

5 files changed

+212
-15
lines changed

5 files changed

+212
-15
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/vendor/
2+
.idea/

src/BlizzardClient.php

Lines changed: 106 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace BlizzardApi;
44

5+
use GuzzleHttp\Client;
56
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
67
use Symfony\Component\OptionsResolver\OptionsResolver;
78

@@ -13,21 +14,27 @@
1314
class BlizzardClient
1415
{
1516
const API_URL_PATTERN = 'https://region.api.battle.net';
17+
const API_ACCESS_TOKEN_URL_PATTERN = 'https://region.battle.net/oauth/token';
1618

1719
/**
1820
* @var string $apiUrl Blizzard API url
1921
*/
2022
private $apiUrl;
2123

24+
/**
25+
* @var string $apiAccessTokenUrl Blizzard API Access Token url
26+
*/
27+
private $apiAccessTokenUrl;
28+
2229
/**
2330
* @var string $apiKey API key
2431
*/
2532
private $apiKey;
2633

2734
/**
28-
* @var string $accessToken Access token
35+
* @var \BlizzardApi\Tokens\Access[] $accessTokens Access tokens
2936
*/
30-
private $accessToken;
37+
private $accessTokens;
3138

3239
/**
3340
* @var string $locale Locale
@@ -43,17 +50,17 @@ class BlizzardClient
4350
* BlizzardClient constructor
4451
*
4552
* @param string $apiKey API key
53+
* @param string $apiSecret API Secret key
4654
* @param string $region Region
4755
* @param string $locale Locale
48-
* @param null|string $accessToken OAuth access token
4956
*/
50-
public function __construct($apiKey, $region = 'us', $locale = 'en_us', $accessToken = null)
57+
public function __construct($apiKey, $apiSecret, $region = 'us', $locale = 'en_us')
5158
{
5259
$options = [
5360
'apiKey' => $apiKey,
61+
'apiSecret' => $apiSecret,
5462
'region' => strtolower($region),
55-
'locale' => strtolower($locale),
56-
'accessToken' => $accessToken,
63+
'locale' => strtolower($locale)
5764
];
5865

5966
$resolver = (new OptionsResolver());
@@ -62,11 +69,12 @@ public function __construct($apiKey, $region = 'us', $locale = 'en_us', $accessT
6269
$options = $resolver->resolve($options);
6370

6471
$this->apiKey = $options['apiKey'];
72+
$this->apiSecret = $options['apiSecret'];
6573
$this->region = $options['region'];
6674
$this->locale = $options['locale'];
67-
$this->accessToken = $options['accessToken'];
6875

6976
$this->updateApiUrl($options['region']);
77+
$this->updateApiAccessTokenUrl($options['region']);
7078
}
7179

7280
/**
@@ -79,6 +87,16 @@ public function getApiUrl()
7987
return $this->apiUrl;
8088
}
8189

90+
/**
91+
* Get api Access Token url
92+
*
93+
* @return string Api Access Token url
94+
*/
95+
public function getApiAccessTokenUrl()
96+
{
97+
return $this->apiAccessTokenUrl;
98+
}
99+
82100
/**
83101
* Get api key
84102
*
@@ -103,6 +121,30 @@ public function setApiKey($apiKey)
103121
return $this;
104122
}
105123

124+
/**
125+
* Get api secret
126+
*
127+
* @return string Api secret
128+
*/
129+
public function getApiSecret()
130+
{
131+
return $this->apiSecret;
132+
}
133+
134+
/**
135+
* Set api secret
136+
*
137+
* @param string $apiSecret Api secret
138+
*
139+
* @return $this
140+
*/
141+
public function setApiSecret($apiSecret)
142+
{
143+
$this->apiSecret = $apiSecret;
144+
145+
return $this;
146+
}
147+
106148
/**
107149
* Get region
108150
*
@@ -125,6 +167,7 @@ public function setRegion($region)
125167
$this->region = strtolower($region);
126168

127169
$this->updateApiUrl($region);
170+
$this->updateApiAccessTokenUrl($region);
128171

129172
return $this;
130173
}
@@ -160,19 +203,27 @@ public function setLocale($locale)
160203
*/
161204
public function getAccessToken()
162205
{
163-
return $this->accessToken;
206+
if ($this->accessTokens == null) {
207+
$this->accessTokens = [];
208+
}
209+
210+
if (!array_key_exists($this->getRegion(), $this->accessTokens)) {
211+
$this->accessTokens[$this->getRegion()] = $this->requestAccessToken();
212+
}
213+
214+
return $this->accessTokens[$this->getRegion()]->getToken();
164215
}
165216

166217
/**
167218
* Set access token
168219
*
169-
* @param null|string $accessToken Access token
220+
* @param null|Tokens\Access $accessToken Access token
170221
*
171222
* @return $this
172223
*/
173-
public function setAccessToken($accessToken)
224+
public function setAccessToken(Tokens\Access $accessToken)
174225
{
175-
$this->accessToken = $accessToken;
226+
$this->accessTokens[$this->getRegion()] = $accessToken;
176227

177228
return $this;
178229
}
@@ -191,6 +242,20 @@ private function updateApiUrl($region)
191242
$this->apiUrl = str_replace('region', strtolower($region), self::API_URL_PATTERN);
192243
}
193244

245+
/**
246+
* Update API Access Token url
247+
*
248+
* Update API Access Token url by replacing region in API url pattern
249+
*
250+
* @param string $region Region
251+
*
252+
* @return $this
253+
*/
254+
private function updateApiAccessTokenUrl($region)
255+
{
256+
$this->apiAccessTokenUrl = str_replace('region', strtolower($region), self::API_ACCESS_TOKEN_URL_PATTERN);
257+
}
258+
194259
/**
195260
* Configure options
196261
*
@@ -213,12 +278,39 @@ private function configureOptions(OptionsResolver $resolver, $region)
213278
);
214279
}
215280

216-
$resolver->setRequired(['apiKey', 'region', 'locale', 'accessToken'])
281+
$resolver->setRequired(['apiKey', 'apiSecret', 'region', 'locale'])
217282
->setAllowedTypes('apiKey', 'string')
283+
->setAllowedTypes('apiSecret', 'string')
218284
->setAllowedTypes('region', 'string')
219285
->setAllowedValues('region', array_keys(GeoData::$list))
220286
->setAllowedTypes('locale', 'string')
221-
->setAllowedValues('locale', $locales)
222-
->setAllowedTypes('accessToken', ['null', 'string']);
287+
->setAllowedValues('locale', $locales);
223288
}
289+
290+
/**
291+
* Request an Access Token from Blizzard
292+
* @return Tokens\Access
293+
* @throws \HttpResponseException
294+
*/
295+
protected function requestAccessToken()
296+
{
297+
$client = new Client();
298+
299+
$options = [
300+
'form_params' => [
301+
'grant_type' => 'client_credentials',
302+
'client_id' => $this->getApiKey(),
303+
'client_secret' => $this->getApiSecret(),
304+
]
305+
];
306+
307+
$result = $client->post($this->getApiAccessTokenUrl(), $options);
308+
309+
if ($result->getStatusCode() == 200) {
310+
return Tokens\Access::fromJson(json_decode($result->getBody()->getContents()));
311+
} else {
312+
throw new \HttpResponseException("Invalid Response");
313+
}
314+
}
315+
224316
}

src/Service/Service.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ protected function request($urlSuffix, array $options)
5252
$options = $this->generateQueryOptions($options);
5353

5454
$result = $client->get($this->serviceParam.$urlSuffix, $options);
55-
55+
5656
return $result;
5757
}
5858

src/Tokens/Access.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace BlizzardApi\Tokens;
4+
5+
use BlizzardApi\BlizzardClient;
6+
use BlizzardApi\Tokens\Exceptions\Expired;
7+
use GuzzleHttp\Client;
8+
use GuzzleHttp\Psr7\Response;
9+
10+
/**
11+
* Class Access Token
12+
*
13+
* @author Hristo Mitev <duronrulez@gmail.com>
14+
*/
15+
class Access
16+
{
17+
/**
18+
* @var string $token The access token itself
19+
*/
20+
protected $token;
21+
22+
/**
23+
* @var string $tokenType The type of the token
24+
*/
25+
protected $tokenType;
26+
27+
/**
28+
* @var int $expiresIn The time for the token to expire in seconds
29+
*/
30+
protected $expiresIn;
31+
32+
/**
33+
* @var \DateTime $createdAt when was the token created
34+
*/
35+
protected $createdAt;
36+
37+
/**
38+
* @var \DateTime $expiresAt when is the token expiring
39+
*/
40+
protected $expiresAt;
41+
42+
/**
43+
* Access constructor.
44+
* @param string $accessToken
45+
* @param string $tokenType
46+
* @param int $expiresIn
47+
*/
48+
public function __construct($accessToken, $tokenType, $expiresIn)
49+
{
50+
$this->token = $accessToken;
51+
$this->tokenType = $tokenType;
52+
$this->expiresIn = $expiresIn;
53+
$this->createdAt = new \DateTime();
54+
$this->expiresAt = new \DateTime();;
55+
$this->expiresAt->add(new \DateInterval('PT'.$this->expiresIn.'S'));
56+
}
57+
58+
/**
59+
* Create token from json object
60+
* @param \stdClass $jsonObject
61+
* @return \BlizzardApi\Tokens\Access
62+
*/
63+
public static function fromJson($jsonObject)
64+
{
65+
return new self($jsonObject->access_token, $jsonObject->token_type, $jsonObject->expires_in);
66+
}
67+
68+
/**
69+
* Check if the token is expired
70+
*
71+
* @return bool
72+
*/
73+
public function isExpired()
74+
{
75+
if ($this->expiresAt > new \DateTime()){
76+
return false;
77+
}
78+
79+
return true;
80+
}
81+
82+
/**
83+
* Get the token string
84+
*
85+
* @return string
86+
* @throws Expired
87+
*/
88+
public function getToken()
89+
{
90+
if ($this->isExpired()) {
91+
throw new Expired("Token has expired");
92+
}
93+
94+
return $this->token;
95+
}
96+
}

src/Tokens/Exceptions/Expired.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace BlizzardApi\Tokens\Exceptions;
4+
5+
6+
class Expired extends \Exception {
7+
8+
}

0 commit comments

Comments
 (0)