Test Failed
Push — master ( 7dffd8...7656e9 )
by LEUNG
03:12
created

Jwt::validateToken()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 36
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 7.2269

Importance

Changes 0
Metric Value
cc 7
eloc 19
nc 7
nop 0
dl 0
loc 36
ccs 10
cts 12
cp 0.8333
crap 7.2269
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace xiaodi\JWTAuth;
6
7
use Lcobucci\JWT\Builder;
8
use Lcobucci\JWT\Parser;
9
use Lcobucci\JWT\Token;
10
use Lcobucci\JWT\ValidationData;
11
use think\App;
12
use think\Model;
13
use xiaodi\JWTAuth\Exception\JWTException;
14
use xiaodi\JWTAuth\Exception\JWTInvalidArgumentException;
15
use xiaodi\JWTAuth\Exception\TokenAlreadyEexpired;
16
use xiaodi\JWTAuth\Handle\RequestToken;
17
18
class Jwt
19
{
20
    /**
21
     * @var User
22
     */
23
    private $user;
24
25
    /**
26
     * @var Token
27
     */
28
    private $token;
29
30
    /**
31
     * @var Manager
32
     */
33
    private $manager;
34
35
    /**
36
     * @var Builder
37 15
     */
38
    private $builder;
39 15
40 15
    use \xiaodi\JWTAuth\Traits\Jwt;
0 ignored issues
show
introduced by
The trait xiaodi\JWTAuth\Traits\Jwt requires some properties which are not provided by xiaodi\JWTAuth\Jwt: $injectUser, $request
Loading history...
41
42 15
    public function __construct(App $app, Manager $manager, Builder $builder, User $user)
43 15
    {
44 15
        $this->app = $app;
0 ignored issues
show
Bug Best Practice introduced by
The property app does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
45
        $this->manager = $manager;
46 15
        $this->builder = $builder;
47
        $this->user = $user;
48 15
49
        $config = $this->getConfig();
50 15
        foreach ($config as $key => $v) {
51
            $this->$key = $v;
52
        }
53
    }
54
55
    /**
56
     * 获取jwt配置.
57
     *
58
     * @return array
59
     */
60 12
    public function getConfig(): array
61
    {
62 12
        return $this->app->config->get('jwt.default', []);
63 12
    }
64
65
    /**
66 12
     * 生成 Token.
67 4
     *
68
     * @param array $claims
69 3
     *
70 1
     * @return Token
71
     */
72 2
    public function token(array $claims): Token
73
    {
74
        $uniqid = $this->makeTokenId($claims);
75 10
76 10
        $this->builder->setIssuer($this->iss())
0 ignored issues
show
Deprecated Code introduced by
The function Lcobucci\JWT\Builder::setIssuedAt() has been deprecated: This method will be removed on v4 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

76
        /** @scrutinizer ignore-deprecated */ $this->builder->setIssuer($this->iss())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Deprecated Code introduced by
The function Lcobucci\JWT\Builder::setIssuer() has been deprecated: This method will be removed on v4 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

76
        /** @scrutinizer ignore-deprecated */ $this->builder->setIssuer($this->iss())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Deprecated Code introduced by
The function Lcobucci\JWT\Builder::setAudience() has been deprecated: This method will be removed on v4 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

76
        /** @scrutinizer ignore-deprecated */ $this->builder->setIssuer($this->iss())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Deprecated Code introduced by
The function Lcobucci\JWT\Builder::setId() has been deprecated: This method will be removed on v4 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

76
        /** @scrutinizer ignore-deprecated */ $this->builder->setIssuer($this->iss())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Deprecated Code introduced by
The function Lcobucci\JWT\Builder::setNotBefore() has been deprecated: This method will be removed on v4 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

76
        /** @scrutinizer ignore-deprecated */ $this->builder->setIssuer($this->iss())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Deprecated Code introduced by
The function Lcobucci\JWT\Builder::setExpiration() has been deprecated: This method will be removed on v4 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

76
        /** @scrutinizer ignore-deprecated */ $this->builder->setIssuer($this->iss())

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Bug introduced by
Are you sure the usage of $this->iss() targeting xiaodi\JWTAuth\Jwt::iss() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
$this->iss() of type void is incompatible with the type string expected by parameter $issuer of Lcobucci\JWT\Builder::setIssuer(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

76
        $this->builder->setIssuer(/** @scrutinizer ignore-type */ $this->iss())
Loading history...
77 10
            ->setAudience($this->aud())
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->aud() targeting xiaodi\JWTAuth\Jwt::aud() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
$this->aud() of type void is incompatible with the type string expected by parameter $audience of Lcobucci\JWT\Builder::setAudience(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

77
            ->setAudience(/** @scrutinizer ignore-type */ $this->aud())
Loading history...
78 10
            ->setId($uniqid, true)
79
            ->setIssuedAt(time())
80 10
            ->setNotBefore(time() + $this->notBefore())
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->notBefore() targeting xiaodi\JWTAuth\Jwt::notBefore() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
81 10
            ->setExpiration(time() + $this->ttl());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->ttl() targeting xiaodi\JWTAuth\Jwt::ttl() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
82
83
        foreach ($claims as $key => $claim) {
84 10
            $this->builder->set($key, $claim);
0 ignored issues
show
Deprecated Code introduced by
The function Lcobucci\JWT\Builder::set() has been deprecated: This method will be removed on v4 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

84
            /** @scrutinizer ignore-deprecated */ $this->builder->set($key, $claim);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
85
        }
86 9
87 2
        $token = $this->builder->getToken($this->getSigner(), $this->makeSignerKey());
88
89
        $this->manager->login($token);
90 9
91
        return $token;
92
    }
93
94
    /**
95
     * 生成 Token ID.
96
     *
97
     * @param array $claims
98
     *
99
     * @return string
100 6
     */
101
    private function makeTokenId(array $claims): string
102
    {
103 6
        if (empty($claims[$this->getUniqidKey()])) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getUniqidKey() targeting xiaodi\JWTAuth\Jwt::getUniqidKey() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
104 1
            throw new JWTException('用户唯一值·uniqidKey·未配置', 500);
105 1
        }
106
107
        return (string) $claims[$this->getUniqidKey()];
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getUniqidKey() targeting xiaodi\JWTAuth\Jwt::getUniqidKey() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
108 6
    }
109
110
    /**
111
     * 获取 当前用户.
112
     *
113
     * @return Model
114
     */
115
    public function user(): Model
116
    {
117
        return $this->user->get();
118
    }
119
120
    /**
121
     * 刷新 Token.
122
     *
123
     * @param Token $token
124
     * @return Token
125
     */
126
    public function refresh(Token $token = null): Token
127
    {
128
        $token = $token ?: $this->getRequestToken();
129
130
        $claims = $token->getClaims();
131
132
        unset($claims['iat']);
133
        unset($claims['jti']);
134
        unset($claims['nbf']);
135
        unset($claims['exp']);
136
        unset($claims['iss']);
137
        unset($claims['aud']);
138
139
        // 加入黑名单
140
        $this->manager->refresh($token);
141
142
        return $this->token($claims);
143
    }
144
145
    /**
146
     * 自动获取请求下的Token.
147
     *
148 5
     * @return Token
149
     */
150
    protected function getRequestToken(): Token
151 5
    {
152
        $requestToken = new RequestToken($this->app);
153
154
        $token = $requestToken->getToken($this->type());
155
156 5
        try {
157
            $token = (new Parser())->parse($token);
158
        } catch (\InvalidArgumentException $e) {
159 5
            throw new JWTInvalidArgumentException('此 Token 解析失败', 500);
160
        }
161 3
162 1
        return $token;
163
    }
164
165
    /**
166 2
     * 解析 Token.
167 1
     *
168
     * @return Token
169 1
     */
170
    public function parseToken(): Token
171 1
    {
172 1
        $token = $this->getRequestToken();
173 2
174
        return $token;
175
    }
176 3
177
    /**
178
     * 登出.
179
     * @param Token $token
180 2
     * @return void
181
     */
182
    public function logout(Token $token = null)
183 5
    {
184
        $this->token = $token ?: $this->getRequestToken();
185
186 5
        $this->manager->logout($this->token);
187 1
    }
188
189
    /**
190
     * 验证 Token.
191 4
     *
192 4
     * @param Token $token
193 1
     *
194
     * @return bool
195 3
     */
196
    public function verify(Token $token = null)
197
    {
198
        $this->token = $token ?: $this->getRequestToken();
199
200
        try {
201
            $this->validateToken();
202
        } catch (\BadMethodCallException $e) {
203
            throw new JWTException('此 Token 未进行签名', 500);
204
        }
205 2
206
        return true;
207 2
    }
208 2
209
    /**
210 2
     * 效验 Token.
211 2
     *
212
     * @return void
213
     */
214
    protected function validateToken()
215
    {
216
        // 验证密钥是否与创建签名的密钥一致
217
        if (false === $this->token->verify($this->getSigner(), $this->makeSignerKey())) {
0 ignored issues
show
Bug introduced by
$this->makeSignerKey() of type Lcobucci\JWT\Signer\Key is incompatible with the type string expected by parameter $key of Lcobucci\JWT\Token::verify(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

217
        if (false === $this->token->verify($this->getSigner(), /** @scrutinizer ignore-type */ $this->makeSignerKey())) {
Loading history...
218
            throw new JWTException('此 Token 与 密钥不匹配', 500);
219
        }
220 1
221
        // 是否可用
222 1
        $exp = $this->token->getClaim('nbf');
223
        if (time() < $exp) {
224
            throw new JWTException('此 Token 暂未可用', 500);
225
        }
226
227
        // 是否在黑名单
228
        if ($this->manager->hasBlacklist($this->token)) {
229
            throw new JWTException('此 Token 已注销', 500);
230
        }
231
232
        // 是否已过期
233
        if ($this->token->isExpired()) {
234
            if (time() < ($this->token->getClaim('iat') + $this->refreshTTL())) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->refreshTTL() targeting xiaodi\JWTAuth\Jwt::refreshTTL() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
235
                throw new TokenAlreadyEexpired('Token 已过期,请重新刷新', $this->getAlreadyCode());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getAlreadyCode() targeting xiaodi\JWTAuth\Jwt::getAlreadyCode() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
236
            } else {
237
                throw new TokenAlreadyEexpired('Token 刷新时间已过,请重新登录', $this->getReloginCode());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getReloginCode() targeting xiaodi\JWTAuth\Jwt::getReloginCode() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
238
            }
239
        }
240 1
241
        $data = new ValidationData();
242 1
243
        $jwt_id = $this->token->getHeader('jti');
244 1
        $data->setIssuer($this->iss());
0 ignored issues
show
Bug introduced by
$this->iss() of type void is incompatible with the type string expected by parameter $issuer of Lcobucci\JWT\ValidationData::setIssuer(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

244
        $data->setIssuer(/** @scrutinizer ignore-type */ $this->iss());
Loading history...
Bug introduced by
Are you sure the usage of $this->iss() targeting xiaodi\JWTAuth\Jwt::iss() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
245 1
        $data->setAudience($this->aud());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->aud() targeting xiaodi\JWTAuth\Jwt::aud() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
$this->aud() of type void is incompatible with the type string expected by parameter $audience of Lcobucci\JWT\ValidationData::setAudience(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

245
        $data->setAudience(/** @scrutinizer ignore-type */ $this->aud());
Loading history...
246 1
        $data->setId($jwt_id);
247 1
248 1
        if (!$this->token->validate($data)) {
249 1
            throw new JWTException('此 Token 效验不通过', 500);
250
        }
251 1
    }
252
}
253