Completed
Branch develop (120cb2)
by Wisoot
02:02
created

src/JwtGuard.php (1 issue)

Check that there are no missing implementations for abstract methods

Bug Major

Upgrade to new PHP Analysis Engine

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
0 ignored issues
show
There is at least one abstract method in this class. Maybe declare it as abstract, or implement the remaining methods: check, guest, id, setUser
Loading history...
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    Tymon\JWTAuth\Payload    $payload
107
     * @return    Illuminate\Contracts\Auth\Authenticatable
108
     */
109
    protected function getUserByPayload(Payload $payload)
110
    {
111
        return $this->provider->retrieveById($payload['sub']);
112
    }
113
114
    /**
115
     * Retrieve the user by the given token.
116
     *
117
     * @param    string    $token
118
     * @return    Illuminate\Contracts\Auth\Authenticatable
119
     */
120
    public function getUserByToken($token)
121
    {
122
        $payload = $this->getPayloadOfToken($token);
123
124
        return $this->getUserByPayload($payload);
125
    }
126
127
    /**
128
     * Determine whether the user has a token attached.
129
     *
130
     * @param \Illuminate\Contracts\Auth\Authenticatable   $user
131
     * @param  Tymon\JWTAuth\Payload  $payload
132
     * @return    boolean
133
     */
134
    protected function userHasToken($user, Payload $payload)
135
    {
136
        return $this->tokenManager->check($user->getAuthIdentifier(), $payload['jti']);
137
    }
138
139
    /**
140
     * Validate a user's credentials.
141
     *
142
     * @param  array  $credentials
143
     * @return bool
144
     */
145
    public function validate(array $credentials = [])
146
    {
147
        return $this->attempt($credentials, false);
148
    }
149
150
    /**
151
     * Attempt to authenticate a user using the given credentials.
152
     *
153
     * @param  array  $credentials
154
     * @param  bool   $login
155
     * @return bool
156
     */
157
    public function attempt(array $credentials = [], $login = true)
158
    {
159
        $this->fireAttemptEvent($credentials, $login);
160
161
        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
162
163
        // If an implementation of UserInterface was returned, we'll ask the provider
164
        // to validate the user against the given credentials, and if they are in
165
        // fact valid we'll log the users into the application and return true.
166
        if ($this->hasValidCredentials($user, $credentials)) {
167
            if ($login) {
168
                $this->login($user);
169
            }
170
171
            return true;
172
        }
173
174
        return false;
175
    }
176
177
    /**
178
     * Determine if the user matches the credentials.
179
     *
180
     * @param  mixed  $user
181
     * @param  array  $credentials
182
     * @return bool
183
     */
184
    protected function hasValidCredentials($user, $credentials)
185
    {
186
        return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
187
    }
188
189
    /**
190
     * Fire the attempt event with the arguments.
191
     *
192
     * @param  array  $credentials
193
     * @param  bool  $login
194
     * @return void
195
     */
196
    protected function fireAttemptEvent(array $credentials, $login)
197
    {
198
        if (isset($this->events)) {
199
            $this->events->fire(new Attempting(
200
                $credentials, false, $login
201
            ));
202
        }
203
    }
204
205
    /**
206
     * Register an authentication attempt event listener.
207
     *
208
     * @param  mixed  $callback
209
     * @return void
210
     */
211
    public function attempting($callback)
212
    {
213
        if (isset($this->events)) {
214
            $this->events->listen(Attempting::class, $callback);
215
        }
216
    }
217
218
    /**
219
     * Log a user into the application.
220
     *
221
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
222
     * @return void
223
     */
224
    public function login(AuthenticatableContract $user)
225
    {
226
        $userId = $user->getAuthIdentifier();
227
        $token = $this->generateTokenForUserId($userId);
228
229
        // If we have an event dispatcher instance set we will fire an event so that
230
        // any listeners will hook into the authentication events and run actions
231
        // based on the login and logout events fired from the guard instances.
232
        $this->fireLoginEvent($user);
233
234
        $this->setToken($token);
235
        $this->setUser($user);
236
    }
237
238
    /**
239
     * generateTokenForUser method
240
     *
241
     * @param int $userId
242
     * @return string
243
     */
244
    protected function generateTokenForUserId($userId)
245
    {
246
        $payload = app('tymon.jwt.payload.factory')->make(['sub' => $userId]);
247
        $token = app('tymon.jwt.auth')->encode($payload);
248
        $this->tokenManager->add($userId, $payload['jti']);
249
250
        return $token->get();
251
    }
252
253
    /**
254
     * Fire the login event if the dispatcher is set.
255
     *
256
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
257
     * @param  bool  $remember
258
     * @return void
259
     */
260
    protected function fireLoginEvent($user, $remember = false)
261
    {
262
        if (isset($this->events)) {
263
            $this->events->fire(new Login($user, $remember));
264
        }
265
    }
266
267
    /**
268
     * Log the given user ID into the application.
269
     *
270
     * @param  mixed  $id
271
     * @return \Illuminate\Contracts\Auth\Authenticatable
272
     */
273
    public function loginUsingId($id)
274
    {
275
        $this->login($user = $this->provider->retrieveById($id));
276
277
        return $user;
278
    }
279
280
    /**
281
     * Log the user out of the application.
282
     *
283
     * @return void
284
     */
285 View Code Duplication
    public function logout()
286
    {
287
        if (!$token = $this->getBearerToken()) {
288
            return;
289
        }
290
291
        try {
292
            $payload = $this->getPayloadOfToken($token);
293
294
            if ($user = $this->getUserByPayload($payload)) {
295
                $this->tokenManager->remove($user->getAuthIdentifier(), $payload['jti']);
296
            }
297
298
        } catch (TokenMismatchException $e) { }
299
300
        if (isset($this->events)) {
301
            $this->events->fire(new Logout($this->user));
302
        }
303
304
        // Once we have fired the logout event we will clear the users out of memory
305
        // so they are no longer available as the user is no longer considered as
306
        // being signed into this application and should not be available here.
307
        $this->user = null;
308
        $this->token = null;
309
        $this->loggedOut = true;
310
    }
311
312
    /**
313
     * log this user out from every token
314
     *
315
     * @return void
316
     */
317 View Code Duplication
    public function logoutAll()
318
    {
319
        if (!$token = $this->getBearerToken()) {
320
            return;
321
        }
322
323
        try {
324
            $payload = $this->getPayloadOfToken($token);
325
326
            if ($user = $this->getUserByPayload($payload)) {
327
                $this->tokenManager->removeAll($user->getAuthIdentifier());
328
            }
329
330
        } catch (TokenMismatchException $e) { }
331
332
        if (isset($this->events)) {
333
            $this->events->fire(new Logout($this->user));
334
        }
335
336
        // Once we have fired the logout event we will clear the users out of memory
337
        // so they are no longer available as the user is no longer considered as
338
        // being signed into this application and should not be available here.
339
        $this->user = null;
340
        $this->token = null;
341
        $this->loggedOut = true;
342
    }
343
344
    /**
345
     * setToken method
346
     *
347
     * @param string $token
348
     */
349
    public function setToken($token)
350
    {
351
        $this->token = $token;
352
    }
353
354
    /**
355
     * getToken method
356
     *
357
     * @return null|string
358
     */
359
    public function getToken()
360
    {
361
        return $this->token;
362
    }
363
364
    /**
365
     * getBearerToken method
366
     *
367
     * @return string|null
368
     */
369
    protected function getBearerToken()
370
    {
371
        $header = $this->request->header('Authorization', '');
372
373
        if (starts_with(strtolower($header), 'bearer ')) {
374
            return mb_substr($header, 7, null, 'UTF-8');
375
        }
376
    }
377
378
}