Completed
Push — master ( 1f3e01...3b63e9 )
by Roman
10:06
created

Guard::attempt()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 23
rs 8.7972
1
<?php
2
3
namespace Framgia\Jwt;
4
5
use Carbon\Carbon;
6
use Illuminate\Support\Str;
7
use Lcobucci\JWT\Parser;
8
use Lcobucci\JWT\Builder;
9
use Illuminate\Http\Request;
10
use InvalidArgumentException;
11
use Framgia\Jwt\Contracts\Signer;
12
use Illuminate\Auth\GuardHelpers;
13
use Illuminate\Contracts\Auth\UserProvider;
14
use Framgia\Jwt\Contracts\ProvidesCredentials;
15
use Illuminate\Contracts\Auth\Guard as GuardContract;
16
17
class Guard implements GuardContract
18
{
19
    use GuardHelpers;
20
21
    /**
22
     * The request instance.
23
     *
24
     * @var \Illuminate\Http\Request
25
     */
26
    protected $request;
27
28
    /**
29
     * @var \Framgia\Jwt\Blacklist
30
     */
31
    protected $blacklist;
32
33
    /**
34
     * @var \Framgia\Jwt\Contracts\Signer
35
     */
36
    protected $signer;
37
38
    /**
39
     * Create a new authentication guard.
40
     *
41
     * @param  \Illuminate\Contracts\Auth\UserProvider  $provider
42
     * @param  \Illuminate\Http\Request  $request
43
     * @param  \Framgia\Jwt\Blacklist  $blacklist
44
     * @param  \Framgia\Jwt\Contracts\Signer  $signer
45
     */
46
    public function __construct(
47
        UserProvider $provider,
48
        Request $request,
1 ignored issue
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
49
        Blacklist $blacklist,
50
        Signer $signer
51
    )
52
    {
53
        $this->request = $request;
54
        $this->provider = $provider;
55
        $this->blacklist = $blacklist;
56
        $this->signer = $signer;
57
    }
58
59
    /**
60
     * Get the currently authenticated user.
61
     *
62
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
63
     */
64
    public function user()
65
    {
66
        // If we've already retrieved the user for the current request we can just
67
        // return it back immediately. We do not want to fetch the user data on
68
        // every call to this method because that would be tremendously slow.
69
        if (! is_null($this->user)) {
70
            return $this->user;
71
        }
72
73
        $user = null;
74
75
        $token = $this->getTokenForRequest();
76
77
        if (! is_null($token)) {
78
            $user = $this->provider->retrieveById($token->getClaim('sub'));
79
        }
80
81
        return $this->user = $user;
82
    }
83
84
    /**
85
     * Get the token for the current request.
86
     *
87
     * @return \Lcobucci\JWT\Token
88
     */
89 View Code Duplication
    protected function getTokenForRequest()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
90
    {
91
        $token = $this->request->bearerToken();
92
93
        if (empty($token)) {
94
            return null;
95
        }
96
97
        try {
98
            $token = (new Parser())->parse($token);
99
100
            if (!$this->signer->verify($token)) {
101
                return null;
102
            }
103
        } catch (InvalidArgumentException $e) {
104
            return null;
105
        }
106
107
        return $token;
108
    }
109
110
    /**
111
     * Validate a user's credentials.
112
     *
113
     * @param  array  $credentials
114
     * @return bool
115
     */
116
    public function validate(array $credentials = [])
117
    {
118
        $user = $this->provider->retrieveByCredentials($credentials);
119
        if (!is_null($user) && $this->provider->validateCredentials($user, $credentials)) {
120
            $this->user = $user;
121
            return true;
122
        }
123
124
        return false;
125
    }
126
127
    /**
128
     * @param array $credentials
129
     * @return \Lcobucci\JWT\Token|null
130
     */
131
    public function attempt(array $credentials)
132
    {
133
        if (!$this->validate($credentials)) {
134
            return null;
135
        }
136
137
        $builder = new Builder();
138
139
        $id = $this->user->getAuthIdentifier();
140
        $builder->setSubject($id);
141
142
        if ($this->user instanceof ProvidesCredentials) {
143
            foreach($this->user->getCredentials() as $key => $value) {
144
                $builder->set($key, $value);
145
            }
146
        }
147
148
        $builder->setExpiration(Carbon::now()->addDay()->timestamp);
149
150
        $builder->setId(Str::random());
151
152
        return $this->signer->sign($builder)->getToken();
153
    }
154
155
    /**
156
     * @return bool
157
     */
158 View Code Duplication
    public function logout()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
159
    {
160
        $token = $this->request->bearerToken();
161
162
        if (empty($token)) {
163
            return true;
164
        }
165
166
        try {
167
            $token = (new Parser())->parse($token);
168
        } catch (InvalidArgumentException $e) {
169
            return false;
170
        }
171
172
        return $this->blacklist->add($token);
173
    }
174
175
    /**
176
     * Set the current request instance.
177
     *
178
     * @param  \Illuminate\Http\Request  $request
179
     * @return $this
180
     */
181
    public function setRequest(Request $request)
1 ignored issue
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
182
    {
183
        $this->request = $request;
184
185
        return $this;
186
    }
187
}
188