Guard   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 300
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 5
Bugs 0 Features 3
Metric Value
wmc 34
c 5
b 0
f 3
lcom 1
cbo 12
dl 0
loc 300
rs 9.2

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A token() 0 8 2
A refresh() 0 12 2
A setToken() 0 7 1
B user() 0 23 4
A setUser() 0 7 1
A login() 0 4 1
A getTokenForRequest() 0 20 4
A validate() 0 10 3
A attempt() 0 8 2
A createTokenForUser() 0 17 2
A logout() 0 17 3
A setRequest() 0 6 1
B applyClaims() 0 24 6
A getExpirationTimestamp() 0 4 1
1
<?php
2
3
namespace Framgia\Jwt;
4
5
use Carbon\Carbon;
6
use Framgia\Jwt\Contracts\ChecksClaims;
7
use Illuminate\Contracts\Auth\Authenticatable;
8
use Illuminate\Support\Str;
9
use Lcobucci\JWT\Claim;
10
use Lcobucci\JWT\Parser;
11
use Lcobucci\JWT\Builder;
12
use Illuminate\Http\Request;
13
use InvalidArgumentException;
14
use Framgia\Jwt\Contracts\Signer;
15
use Illuminate\Auth\GuardHelpers;
16
use Illuminate\Contracts\Auth\UserProvider;
17
use Framgia\Jwt\Contracts\ProvidesCredentials;
18
use Illuminate\Contracts\Auth\Guard as GuardContract;
19
use Lcobucci\JWT\Token;
20
21
class Guard implements GuardContract
22
{
23
    use GuardHelpers;
24
25
    /**
26
     * Default claims.
27
     * 
28
     * @var array
29
     */
30
    protected $claims = [
31
        'aud' => 'Audience',
32
        'exp' => 'Expiration',
33
        'jti' => 'Id',
34
        'iat' => 'IssuedAt',
35
        'iss' => 'Issuer',
36
        'nbf' => 'NotBefore',
37
        'sub' => 'Subject',
38
    ];
39
40
    /**
41
     * The request instance.
42
     *
43
     * @var \Illuminate\Http\Request
44
     */
45
    protected $request;
46
47
    /**
48
     * @var \Framgia\Jwt\Blacklist
49
     */
50
    protected $blacklist;
51
52
    /**
53
     * @var \Framgia\Jwt\Contracts\Signer
54
     */
55
    protected $signer;
56
57
    /**
58
     * @var \Lcobucci\JWT\Token
59
     */
60
    protected $token;
61
62
    /**
63
     * Create a new authentication guard.
64
     *
65
     * @param  \Illuminate\Contracts\Auth\UserProvider  $provider
66
     * @param  \Illuminate\Http\Request  $request
67
     * @param  \Framgia\Jwt\Blacklist  $blacklist
68
     * @param  \Framgia\Jwt\Contracts\Signer  $signer
69
     */
70
    public function __construct(
71
        UserProvider $provider,
72
        Request $request,
73
        Blacklist $blacklist,
74
        Signer $signer
75
    )
76
    {
77
        $this->request = $request;
78
        $this->provider = $provider;
79
        $this->blacklist = $blacklist;
80
        $this->signer = $signer;
81
    }
82
83
    /**
84
     * Get current token.
85
     * 
86
     * @return \Lcobucci\JWT\Token
87
     */
88
    public function token()
89
    {
90
        if (empty($this->token)) {
91
            $this->token = $this->getTokenForRequest();
92
        }
93
94
        return $this->token;
95
    }
96
97
    /**
98
     * Refresh token expiration with same ID.
99
     * 
100
     * @param  \Lcobucci\JWT\Token|null  $token
101
     * @return \Lcobucci\JWT\Token
102
     */
103
    public function refresh(Token $token = null)
104
    {
105
        if (is_null($token)) {
106
            $token = $this->token();
107
        }
108
        
109
        $builder = $this->applyClaims($token->getClaims());
0 ignored issues
show
Bug introduced by
It seems like $token is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
110
        
111
        $builder->setExpiration($this->getExpirationTimestamp());
112
113
        return $this->signer->sign($builder)->getToken();
114
    }
115
116
    public function setToken(Token $token)
117
    {
118
        $this->token = $token;
119
        $this->user = null;
120
121
        return $this;
122
    }
123
124
    /**
125
     * Get the currently authenticated user.
126
     *
127
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
128
     */
129
    public function user()
130
    {
131
        // If we've already retrieved the user for the current request we can just
132
        // return it back immediately. We do not want to fetch the user data on
133
        // every call to this method because that would be tremendously slow.
134
        if (! is_null($this->user)) {
135
            return $this->user;
136
        }
137
138
        $user = null;
139
140
        $token = $this->token();
141
142
        if (! is_null($token)) {
143
            if ($this->provider instanceof ChecksClaims) {
144
                $user = $this->provider->retrieveByClaims($token->getClaims());
145
            } else {
146
                $user = $this->provider->retrieveById($token->getClaim('sub'));
147
            }
148
        }
149
150
        return $this->user = $user;
151
    }
152
153
    public function setUser(Authenticatable $user)
154
    {
155
        $this->user = $user;
156
        $this->token = $this->createTokenForUser($this->user);
157
158
        return $this;
159
    }
160
161
    public function login(Authenticatable $user)
162
    {
163
        return $this->setUser($user);
164
    }
165
166
    /**
167
     * Get the token for the current request.
168
     *
169
     * @return \Lcobucci\JWT\Token
170
     */
171
    protected function getTokenForRequest()
172
    {
173
        $token = $this->request->bearerToken();
174
175
        if (empty($token)) {
176
            return null;
177
        }
178
179
        try {
180
            $token = (new Parser())->parse($token);
181
182
            if (!$this->signer->verify($token)) {
183
                return null;
184
            }
185
        } catch (InvalidArgumentException $e) {
186
            return null;
187
        }
188
189
        return $token;
190
    }
191
192
    /**
193
     * Validate a user's credentials.
194
     *
195
     * @param  array  $credentials
196
     * @return bool
197
     */
198
    public function validate(array $credentials = [])
199
    {
200
        $user = $this->provider->retrieveByCredentials($credentials);
201
        if (!is_null($user) && $this->provider->validateCredentials($user, $credentials)) {
202
            $this->user = $user;
203
            return true;
204
        }
205
206
        return false;
207
    }
208
209
    /**
210
     * @param array $credentials
211
     * @return \Lcobucci\JWT\Token|null
212
     */
213
    public function attempt(array $credentials)
214
    {
215
        if (!$this->validate($credentials)) {
216
            return null;
217
        }
218
219
        return $this->token = $this->createTokenForUser($this->user);
220
    }
221
222
    /**
223
     * @param  Authenticatable  $user
224
     * @return Token
225
     */
226
    public function createTokenForUser(Authenticatable $user)
227
    {
228
        $builder = new Builder();
229
230
        $id = $user->getAuthIdentifier();
231
        $builder->setSubject($id);
232
233
        if ($user instanceof ProvidesCredentials) {
234
            $builder = $this->applyClaims($user->getCredentials(), true, $builder);
235
        }
236
237
        $builder->setExpiration($this->getExpirationTimestamp());
238
239
        $builder->setId(Str::random());
240
241
        return $this->signer->sign($builder)->getToken();
242
    }
243
244
    /**
245
     * @return bool
246
     */
247
    public function logout()
248
    {
249
        $token = $this->getTokenForRequest();
250
251
        if (empty($token)) {
252
            $result = true;
253
        } else {
254
            $result = $this->blacklist->add($token);
255
        }
256
257
        if ($result) {
258
            $this->token = null;
259
            $this->user = null;
260
        }
261
262
        return $result;
263
    }
264
265
    /**
266
     * Set the current request instance.
267
     *
268
     * @param  \Illuminate\Http\Request  $request
269
     * @return $this
270
     */
271
    public function setRequest(Request $request)
272
    {
273
        $this->request = $request;
274
275
        return $this;
276
    }
277
278
    /**
279
     * Apply claims to builder.
280
     * 
281
     * @param  array  $claims
282
     * @param  bool  $protect
283
     * @param  \Lcobucci\JWT\Builder|null  $builder
284
     * @return \Lcobucci\JWT\Builder
285
     */
286
    protected function applyClaims(array $claims, $protect = false, Builder $builder = null)
287
    {
288
        if (is_null($builder)) {
289
            $builder = new Builder();
290
        }
291
292
        foreach ($claims as $key => $value) {
293
294
            if ($value instanceof Claim) {
295
                $key = $value->getName();
296
                $value = $value->getValue();
297
            }
298
299
            if (array_key_exists($key, $this->claims)) {
300
                if (!$protect) {
301
                    $builder->{'set' . $this->claims[$key]}($value);
302
                }
303
            } else {
304
                $builder->set($key, $value);
305
            }
306
        }
307
308
        return $builder;
309
    }
310
311
    /**
312
     * Get token expiration timestamp.
313
     * 
314
     * @return int
315
     */
316
    protected function getExpirationTimestamp()
317
    {
318
        return Carbon::now()->addDay()->timestamp;
319
    }
320
}
321