These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace WWON\JwtGuard; |
||
4 | |||
5 | use Illuminate\Auth\Events\Attempting; |
||
6 | use Illuminate\Auth\Events\Login; |
||
7 | use Illuminate\Auth\Events\Logout; |
||
8 | use Illuminate\Auth\GuardHelpers; |
||
9 | use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; |
||
10 | use Illuminate\Contracts\Auth\Guard; |
||
11 | use Illuminate\Contracts\Auth\UserProvider; |
||
12 | use Illuminate\Http\Request; |
||
13 | use Illuminate\Session\TokenMismatchException; |
||
14 | use Tymon\JWTAuth\Exceptions\JWTException; |
||
15 | use Tymon\JWTAuth\Payload; |
||
16 | |||
17 | class JwtGuard implements Guard |
||
18 | { |
||
19 | |||
20 | use GuardHelpers; |
||
21 | |||
22 | /** |
||
23 | * @var string |
||
24 | */ |
||
25 | protected $token; |
||
26 | |||
27 | /** |
||
28 | * @var TokenManager |
||
29 | */ |
||
30 | protected $tokenManager; |
||
31 | |||
32 | /** |
||
33 | * @var Request |
||
34 | */ |
||
35 | protected $request; |
||
36 | |||
37 | /** |
||
38 | * Indicates if the logout method has been called. |
||
39 | * |
||
40 | * @var bool |
||
41 | */ |
||
42 | protected $loggedOut = false; |
||
43 | |||
44 | /** |
||
45 | * JwtGuard constructor |
||
46 | * |
||
47 | * @param UserProvider $provider |
||
48 | * @param TokenManager $tokenManager |
||
49 | * @param Request|null $request |
||
50 | */ |
||
51 | public function __construct( |
||
52 | UserProvider $provider, |
||
53 | TokenManager $tokenManager, |
||
54 | Request $request = null |
||
55 | ) { |
||
56 | $this->provider = $provider; |
||
57 | $this->tokenManager = $tokenManager; |
||
58 | $this->request = $request; |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * Get the currently authenticated user. |
||
63 | * |
||
64 | * @return \Illuminate\Contracts\Auth\Authenticatable|null |
||
65 | */ |
||
66 | public function user() |
||
67 | { |
||
68 | // If we've already retrieved the user for the current request we can just |
||
69 | // return it back immediately. We do not want to fetch the user data on |
||
70 | // every call to this method because that would be tremendously slow. |
||
71 | if ($this->user) { |
||
72 | return $this->user; |
||
73 | } |
||
74 | |||
75 | if (!$token = $this->getBearerToken()) { |
||
76 | return $this->user = null; |
||
77 | } |
||
78 | |||
79 | try { |
||
80 | $payload = $this->getPayloadOfToken($token); |
||
81 | $user = $this->getUserByPayload($payload); |
||
82 | |||
83 | $this->user = $this->userHasToken($user, $payload) ? $user : null; |
||
84 | |||
85 | } catch (JWTException $e) { |
||
86 | $this->user = null; |
||
87 | } |
||
88 | |||
89 | return $this->user; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Retrieve the payload of the given token. |
||
94 | * |
||
95 | * @param string $token |
||
96 | * @return array |
||
97 | */ |
||
98 | protected function getPayloadOfToken($token) |
||
99 | { |
||
100 | return app('tymon.jwt.auth')->setToken($token)->getPayload(); |
||
101 | } |
||
102 | |||
103 | /** |
||
104 | * Retrieve the user by the given payload. |
||
105 | * |
||
106 | * @param Payload $payload |
||
107 | * @return AuthenticatableContract|null |
||
108 | */ |
||
109 | protected function getUserByPayload(Payload $payload) |
||
110 | { |
||
111 | return $this->provider->retrieveById($payload['sub']); |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * Determine whether the user has a token attached. |
||
116 | * |
||
117 | * @param \Illuminate\Contracts\Auth\Authenticatable $user |
||
118 | * @param Payload $payload |
||
119 | * @return bool |
||
120 | */ |
||
121 | protected function userHasToken($user, Payload $payload) |
||
122 | { |
||
123 | return $this->tokenManager->check($user->getAuthIdentifier(), $payload['jti']); |
||
0 ignored issues
–
show
|
|||
124 | } |
||
125 | |||
126 | /** |
||
127 | * Remove given token from the given user |
||
128 | * |
||
129 | * @param $user |
||
130 | * @param Payload $payload |
||
131 | */ |
||
132 | protected function removeUserToken($user, Payload $payload) |
||
133 | { |
||
134 | $this->tokenManager->remove($user->getAuthIdentifier(), $payload['jti']); |
||
0 ignored issues
–
show
The call to
TokenManager::remove() has too many arguments starting with $payload['jti'] .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the
Loading history...
|
|||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Validate a user's credentials. |
||
139 | * |
||
140 | * @param array $credentials |
||
141 | * @return bool |
||
142 | */ |
||
143 | public function validate(array $credentials = []) |
||
144 | { |
||
145 | return $this->attempt($credentials, false); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Attempt to authenticate a user using the given credentials. |
||
150 | * |
||
151 | * @param array $credentials |
||
152 | * @param bool $login |
||
153 | * @return bool |
||
154 | */ |
||
155 | public function attempt(array $credentials = [], $login = true) |
||
156 | { |
||
157 | $this->fireAttemptEvent($credentials, $login); |
||
158 | |||
159 | $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials); |
||
160 | |||
161 | // If an implementation of UserInterface was returned, we'll ask the provider |
||
162 | // to validate the user against the given credentials, and if they are in |
||
163 | // fact valid we'll log the users into the application and return true. |
||
164 | if ($this->hasValidCredentials($user, $credentials)) { |
||
165 | if ($login) { |
||
166 | $this->login($user); |
||
167 | } |
||
168 | |||
169 | return true; |
||
170 | } |
||
171 | |||
172 | return false; |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * Determine if the user matches the credentials. |
||
177 | * |
||
178 | * @param mixed $user |
||
179 | * @param array $credentials |
||
180 | * @return bool |
||
181 | */ |
||
182 | protected function hasValidCredentials($user, $credentials) |
||
183 | { |
||
184 | return ! is_null($user) && $this->provider->validateCredentials($user, $credentials); |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * Fire the attempt event with the arguments. |
||
189 | * |
||
190 | * @param array $credentials |
||
191 | * @param bool $login |
||
192 | * @return void |
||
193 | */ |
||
194 | protected function fireAttemptEvent(array $credentials, $login) |
||
195 | { |
||
196 | if (isset($this->events)) { |
||
197 | $this->events->fire(new Attempting( |
||
198 | $credentials, false, $login |
||
199 | )); |
||
200 | } |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * Register an authentication attempt event listener. |
||
205 | * |
||
206 | * @param mixed $callback |
||
207 | * @return void |
||
208 | */ |
||
209 | public function attempting($callback) |
||
210 | { |
||
211 | if (isset($this->events)) { |
||
212 | $this->events->listen(Attempting::class, $callback); |
||
213 | } |
||
214 | } |
||
215 | |||
216 | /** |
||
217 | * Log a user into the application. |
||
218 | * |
||
219 | * @param \Illuminate\Contracts\Auth\Authenticatable $user |
||
220 | * @return void |
||
221 | */ |
||
222 | public function login(AuthenticatableContract $user) |
||
223 | { |
||
224 | $userId = $user->getAuthIdentifier(); |
||
225 | $token = $this->generateTokenForUserId($userId); |
||
226 | |||
227 | // If we have an event dispatcher instance set we will fire an event so that |
||
228 | // any listeners will hook into the authentication events and run actions |
||
229 | // based on the login and logout events fired from the guard instances. |
||
230 | $this->fireLoginEvent($user); |
||
231 | |||
232 | $this->setToken($token); |
||
233 | $this->setUser($user); |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * generateTokenForUser method |
||
238 | * |
||
239 | * @param int $userId |
||
240 | * @return string |
||
241 | */ |
||
242 | protected function generateTokenForUserId($userId) |
||
243 | { |
||
244 | $payload = app('tymon.jwt.payload.factory')->make(['sub' => $userId]); |
||
245 | $token = app('tymon.jwt.auth')->encode($payload); |
||
246 | $this->tokenManager->add($userId, $payload['jti']); |
||
0 ignored issues
–
show
$userId is of type integer , but the function expects a object<WWON\JwtGuard\Claim> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
The call to
TokenManager::add() has too many arguments starting with $payload['jti'] .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the
Loading history...
|
|||
247 | |||
248 | return $token->get(); |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * generateTokenForUser method |
||
253 | * |
||
254 | * @param string $token |
||
255 | * @return string |
||
256 | */ |
||
257 | protected function refreshTokenForUser($token) |
||
258 | { |
||
259 | $newToken = app('tymon.jwt.auth')->refresh($token); |
||
260 | $payload = $this->getPayloadOfToken($newToken); |
||
261 | $user = $this->getUserByPayload($payload); |
||
262 | |||
263 | $this->tokenManager->add($user->getAuthIdentifier(), $payload['jti']); |
||
0 ignored issues
–
show
The call to
TokenManager::add() has too many arguments starting with $payload['jti'] .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the
Loading history...
|
|||
264 | |||
265 | return $newToken; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Fire the login event if the dispatcher is set. |
||
270 | * |
||
271 | * @param \Illuminate\Contracts\Auth\Authenticatable $user |
||
272 | * @param bool $remember |
||
273 | * @return void |
||
274 | */ |
||
275 | protected function fireLoginEvent($user, $remember = false) |
||
276 | { |
||
277 | if (isset($this->events)) { |
||
278 | $this->events->fire(new Login($user, $remember)); |
||
279 | } |
||
280 | } |
||
281 | |||
282 | /** |
||
283 | * Log the given user ID into the application. |
||
284 | * |
||
285 | * @param mixed $id |
||
286 | * @return \Illuminate\Contracts\Auth\Authenticatable |
||
287 | */ |
||
288 | public function loginUsingId($id) |
||
289 | { |
||
290 | $this->login($user = $this->provider->retrieveById($id)); |
||
291 | |||
292 | return $user; |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Log the user out of the application. |
||
297 | * |
||
298 | * @return void |
||
299 | */ |
||
300 | View Code Duplication | public function logout() |
|
301 | { |
||
302 | if (!$token = $this->getBearerToken()) { |
||
303 | return; |
||
304 | } |
||
305 | |||
306 | try { |
||
307 | $payload = $this->getPayloadOfToken($token); |
||
308 | |||
309 | if ($user = $this->getUserByPayload($payload)) { |
||
310 | $this->tokenManager->remove($user->getAuthIdentifier(), $payload['jti']); |
||
0 ignored issues
–
show
The call to
TokenManager::remove() has too many arguments starting with $payload['jti'] .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the
Loading history...
|
|||
311 | } |
||
312 | |||
313 | } catch (TokenMismatchException $e) { } |
||
314 | |||
315 | if (isset($this->events)) { |
||
316 | $this->events->fire(new Logout($this->user)); |
||
317 | } |
||
318 | |||
319 | // Once we have fired the logout event we will clear the users out of memory |
||
320 | // so they are no longer available as the user is no longer considered as |
||
321 | // being signed into this application and should not be available here. |
||
322 | $this->user = null; |
||
323 | $this->token = null; |
||
324 | $this->loggedOut = true; |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * log this user out from every token |
||
329 | * |
||
330 | * @return void |
||
331 | */ |
||
332 | View Code Duplication | public function logoutAll() |
|
333 | { |
||
334 | if (!$token = $this->getBearerToken()) { |
||
335 | return; |
||
336 | } |
||
337 | |||
338 | try { |
||
339 | $payload = $this->getPayloadOfToken($token); |
||
340 | |||
341 | if ($user = $this->getUserByPayload($payload)) { |
||
342 | $this->tokenManager->removeAll($user->getAuthIdentifier()); |
||
343 | } |
||
344 | |||
345 | } catch (TokenMismatchException $e) { } |
||
346 | |||
347 | if (isset($this->events)) { |
||
348 | $this->events->fire(new Logout($this->user)); |
||
349 | } |
||
350 | |||
351 | // Once we have fired the logout event we will clear the users out of memory |
||
352 | // so they are no longer available as the user is no longer considered as |
||
353 | // being signed into this application and should not be available here. |
||
354 | $this->user = null; |
||
355 | $this->token = null; |
||
356 | $this->loggedOut = true; |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * Refresh user token |
||
361 | * |
||
362 | * @return string|null |
||
363 | */ |
||
364 | public function refreshToken() |
||
365 | { |
||
366 | if (!$token = $this->getBearerToken()) { |
||
367 | return null; |
||
368 | } |
||
369 | |||
370 | try { |
||
371 | $payload = $this->getPayloadOfToken($token); |
||
372 | $user = $this->getUserByPayload($payload); |
||
373 | |||
374 | $user = $this->userHasToken($user, $payload) ? $user : null; |
||
375 | $this->removeUserToken($user, $payload); |
||
376 | |||
377 | $this->token = $this->refreshTokenForUser($token); |
||
378 | |||
379 | } catch (JWTException $e) { |
||
380 | return null; |
||
381 | } |
||
382 | |||
383 | return $this->token; |
||
384 | } |
||
385 | |||
386 | /** |
||
387 | * setToken method |
||
388 | * |
||
389 | * @param string $token |
||
390 | */ |
||
391 | public function setToken($token) |
||
392 | { |
||
393 | $this->token = $token; |
||
394 | } |
||
395 | |||
396 | /** |
||
397 | * getToken method |
||
398 | * |
||
399 | * @return null|string |
||
400 | */ |
||
401 | public function getToken() |
||
402 | { |
||
403 | return $this->token; |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * getBearerToken method |
||
408 | * |
||
409 | * @return string|null |
||
410 | */ |
||
411 | protected function getBearerToken() |
||
412 | { |
||
413 | $header = $this->request->header('Authorization', ''); |
||
414 | |||
415 | if (starts_with(strtolower($header), 'bearer ')) { |
||
416 | return mb_substr($header, 7, null, 'UTF-8'); |
||
417 | } |
||
418 | } |
||
419 | |||
420 | } |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.