Completed
Push — master ( 7eb1a4...254269 )
by LEUNG
03:41
created

Jwt::parseToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1.125

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
ccs 1
cts 2
cp 0.5
crap 1.125
1
<?php
2
3
declare(strict_types=1);
4
5
namespace xiaodi\JWTAuth;
6
7
use think\App;
8
use Lcobucci\JWT\Builder;
9
use Lcobucci\JWT\ValidationData;
10
use xiaodi\JWTAuth\Manager;
11
use xiaodi\JWTAuth\Exception\HasLoggedException;
12
use xiaodi\JWTAuth\Exception\JWTException;
13
use xiaodi\JWTAuth\Exception\JWTInvalidArgumentException;
14
use xiaodi\JWTAuth\Exception\TokenAlreadyEexpired;
15
use Lcobucci\JWT\Token;
16
use Lcobucci\JWT\Parser;
17
use xiaodi\JWTAuth\Handle\RequestToken;
18
19
class Jwt
20
{
21
    /**
22
     * @var User
23
     */
24
    private $user;
25
26
    /**
27
     * @var Token
28
     */
29
    private $token;
30
31
    /**
32
     * @var Manager
33
     */
34
    private $manager;
35
36
     /**
37 15
     * @var Builder
38
     */
39 15
    private $builder;
40 15
41
    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...
42 15
43 15
    public function __construct(App $app, Manager $manager, Builder $builder)
44 15
    {
45
        $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...
46 15
        $this->manager = $manager;
47
        $this->builder = $builder;
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();
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...
77 10
            ->setAudience($this->aud())
78 10
            ->setId($uniqid, true)
79
            ->setIssuedAt(time())
80 10
            ->setNotBefore(time() + $this->notBefore())
81 10
            ->setExpiration(time() + $this->ttl());
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
     *
96
     * @return String
97
     */
98
    private function makeTokenId(): String
99
    {
100 6
        $uniqid = uniqid();
101
102
        return (string) $uniqid;
103 6
    }
104 1
105 1
    /**
106
     * 获取 当前用户
107
     *
108 6
     * @return User
109
     */
110
    public function user(): User
111
    {
112
        return $this->user;
113
    }
114
115
    /**
116
     * 刷新 Token
117
     *
118
     * @return void
119
     */
120
    public function refresh()
121
    {
122
        $token = $this->getRequestToken();
123
124
        $this->manager->refresh($token);
125
    }
126
127
    /**
128
     * 自动获取请求下的Token
129
     *
130
     * @return Token
131
     */
132
    protected function getRequestToken(): Token
133
    {
134
        $requestToken = new RequestToken($this->app);
135
136
        $token = $requestToken->getToken($this->type());
137
138
        try {
139
            $token = (new Parser())->parse($token);
140
        } catch (\InvalidArgumentException $e) {
141
            throw new JWTInvalidArgumentException('此 Token 解析失败', 500);
142
        }
143
144
        return $token;
145
    }
146
147
    /**
148 5
     * 解析 Token
149
     *
150
     * @return Token
151 5
     */
152
    public function parseToken(): Token
153
    {
154
        $token = $this->getRequestToken();
155
156 5
        return $token;
157
    }
158
159 5
160
    /**
161 3
     * 登出
162 1
     *
163
     * @return void
164
     */
165
    public function logout()
166 2
    {
167 1
        $token = $this->getRequestToken();
168
169 1
        $this->manager->refresh($token);
170
    }
171 1
172 1
    /**
173 2
     * 验证 Token.
174
     *
175
     * @param Token $token
176 3
     * @return bool
177
     */
178
    public function verify(Token $token = null)
179
    {
180 2
        $this->token = $token ?: $this->getRequestToken();
181
182
        try {
183 5
            $this->validateToken();
184
185
            // 是否已过期
186 5
            if ($this->token->isExpired()) {
187 1
                if (time() < ($this->token->getClaim('iat') + $this->refreshTTL())) {
188
                    throw new TokenAlreadyEexpired('Token 已过期,请重新刷新', 401, $this->getAlreadyCode());
189
                } else {
190
                    throw new TokenAlreadyEexpired('Token 刷新时间已过,请重新登录', 401, $this->getReloginCode());
191 4
                }
192 4
            }
193 1
        } catch (\BadMethodCallException $e) {
194
            throw new JWTException('此 Token 未进行签名', 500);
195 3
        }
196
197
        return true;
198
    }
199
200
    /**
201
     * 效验 Token.
202
     *
203
     * @return void
204
     */
205 2
    protected function validateToken()
206
    {
207 2
        // 验证密钥是否与创建签名的密钥一致
208 2
        if (false === $this->token->verify($this->getSigner(), $this->makeKey())) {
0 ignored issues
show
Bug introduced by
The method makeKey() does not exist on xiaodi\JWTAuth\Jwt. ( Ignorable by Annotation )

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

208
        if (false === $this->token->verify($this->getSigner(), $this->/** @scrutinizer ignore-call */ makeKey())) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
209
            throw new JWTException('此 Token 与 密钥不匹配', 500);
210 2
        }
211 2
212
        // 是否可用
213
        $exp = $this->token->getClaim('nbf');
214
        if (time() < $exp) {
215
            throw new JWTException('此 Token 暂未可用', 500);
216
        }
217
218
        $data = new ValidationData();
219
220 1
        $jwt_id = $this->token->getHeader('jti');
221
        $data->setIssuer($this->iss());
222 1
        $data->setAudience($this->aud());
223
        $data->setId($jwt_id);
224
225
        if (!$this->token->validate($data))
226
        {
227
            throw new JWTException('此 Token 效验不通过', 500);
228
        }
229
230
        if ($this->manager->hasBlacklist($this->token)) {
231
            throw new JWTException('此 Token 已注销', 500);
232
        }
233
    }
234
}
235