Issues (44)

src/Jwt.php (18 issues)

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;
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
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...
$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
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...
$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
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
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
            ->set('refreshAt', time() + $this->refreshTTL());
0 ignored issues
show
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...
83
84 10
        foreach ($claims as $key => $claim) {
85
            $this->builder->set($key, $claim);
86 9
        }
87 2
88
        $token = $this->builder->getToken($this->getSigner(), $this->makeSignerKey());
89
90 9
        $this->manager->login($token);
91
92
        return $token;
93
    }
94
95
    /**
96
     * 生成 Token ID.
97
     *
98
     * @param array $claims
99
     *
100 6
     * @return string
101
     */
102
    private function makeTokenId(array $claims): string
103 6
    {
104 1
        if (empty($claims[$this->getUniqidKey()])) {
0 ignored issues
show
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...
105 1
            throw new JWTException('用户唯一值·uniqidKey·未配置', 500);
106
        }
107
108 6
        return (string) $claims[$this->getUniqidKey()];
0 ignored issues
show
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...
109
    }
110
111
    /**
112
     * 获取 当前用户.
113
     *
114
     * @return Model
115
     */
116
    public function user(): Model
117
    {
118
        return $this->user->get();
119
    }
120
121
    /**
122
     * 刷新 Token.
123
     *
124
     * @param Token $token
125
     *
126
     * @return Token
127
     */
128
    public function refresh(Token $token = null): Token
129
    {
130
        $token = $token ?: $this->getRequestToken();
131
132
        $claims = $token->getClaims();
133
134
        unset($claims['iat']);
135
        unset($claims['jti']);
136
        unset($claims['nbf']);
137
        unset($claims['exp']);
138
        unset($claims['iss']);
139
        unset($claims['aud']);
140
141
        // 加入黑名单
142
        $this->manager->refresh($token);
143
144
        return $this->token($claims);
145
    }
146
147
    /**
148 5
     * 自动获取请求下的Token.
149
     *
150
     * @return Token
151 5
     */
152
    protected function getRequestToken(): Token
153
    {
154
        $requestToken = new RequestToken($this->app);
155
156 5
        $token = $requestToken->get($this->type());
157
158
        try {
159 5
            $token = (new Parser())->parse($token);
160
        } catch (\InvalidArgumentException $e) {
161 3
            throw new JWTInvalidArgumentException('此 Token 解析失败', 500);
162 1
        }
163
164
        return $token;
165
    }
166 2
167 1
    /**
168
     * 解析 Token.
169 1
     *
170
     * @return Token
171 1
     */
172 1
    public function parseToken(): Token
173 2
    {
174
        $token = $this->getRequestToken();
175
176 3
        return $token;
177
    }
178
179
    /**
180 2
     * 登出.
181
     *
182
     * @param Token $token
183 5
     *
184
     * @return void
185
     */
186 5
    public function logout(Token $token = null)
187 1
    {
188
        $this->token = $token ?: $this->getRequestToken();
189
190
        $this->manager->logout($this->token);
191 4
    }
192 4
193 1
    /**
194
     * 验证 Token.
195 3
     *
196
     * @param Token $token
197
     *
198
     * @return bool
199
     */
200
    public function verify(Token $token = null)
201
    {
202
        $this->token = $token ?: $this->getRequestToken();
203
204
        try {
205 2
            $this->validateToken();
206
        } catch (\BadMethodCallException $e) {
207 2
            throw new JWTException('此 Token 未进行签名', 500);
208 2
        }
209
210 2
        return true;
211 2
    }
212
213
    /**
214
     * 效验 Token.
215
     *
216
     * @return void
217
     */
218
    protected function validateToken()
219
    {
220 1
        // 是否在黑名单
221
        if ($this->manager->hasBlacklist($this->token)) {
222 1
            throw new TokenAlreadyEexpired('此 Token 已注销,请重新登录', $this->getReloginCode());
0 ignored issues
show
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...
223
        }
224
225
        // 验证密钥是否与创建签名的密钥一致
226
        if (false === $this->token->verify($this->getSigner(), $this->makeSignerKey())) {
0 ignored issues
show
$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

226
        if (false === $this->token->verify($this->getSigner(), /** @scrutinizer ignore-type */ $this->makeSignerKey())) {
Loading history...
227
            throw new JWTException('此 Token 与 密钥不匹配', 500);
228
        }
229
230
        // 是否可用
231
        $exp = $this->token->getClaim('nbf');
232
        if (time() < $exp) {
233
            throw new JWTException('此 Token 暂未可用', 500);
234
        }
235
236
        // 是否已过期
237
        if (true === $this->token->isExpired()) {
238
            if (time() <= $this->token->getClaim('refreshAt')) {
239
                throw new TokenAlreadyEexpired('Token 已过期,请重新刷新'.time().'-'.$this->token->getClaim('refreshAt'), $this->getAlreadyCode());
0 ignored issues
show
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...
240 1
            }
241
242 1
            throw new TokenAlreadyEexpired('Token 刷新时间已过,请重新登录', $this->getReloginCode());
0 ignored issues
show
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...
243
        }
244 1
245 1
        $data = new ValidationData();
246 1
247 1
        $jwt_id = $this->token->getHeader('jti');
248 1
        $data->setIssuer($this->iss());
0 ignored issues
show
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...
$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

248
        $data->setIssuer(/** @scrutinizer ignore-type */ $this->iss());
Loading history...
249 1
        $data->setAudience($this->aud());
0 ignored issues
show
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...
$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

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