Completed
Push — master ( 521d0e...48c1a2 )
by Alexpts
02:17
created

CheckJwtToken   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 16.66%

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 6
dl 0
loc 154
ccs 8
cts 48
cp 0.1666
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A setCheckIp() 0 5 1
A setCookieName() 0 5 1
A setIpAttr() 0 5 1
A setTokenAttr() 0 5 1
A process() 0 22 3
A checkTokenIp() 0 10 4
A getIpFromToken() 0 5 2
A getTokenFromRequest() 0 6 2
A getTokenFromCookie() 0 7 2
A getTokenFromBearerHeader() 0 7 2
1
<?php
2
declare(strict_types=1);
3
4
namespace PTS\CheckJwtToken;
5
6
use Emarref\Jwt\Token;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Server\MiddlewareInterface;
10
use Psr\Http\Server\RequestHandlerInterface;
11
use PTS\JwtService\JwtService;
12
13
class CheckJwtToken implements MiddlewareInterface
14
{
15
16
    /** @var string */
17
    protected $tokenAttr = 'token';
18
    /** @var string */
19
    protected $ipAttr = 'client-ip';
20
    /** @var string */
21
    protected $cookieName = 'auth_token';
22
    /** @var JwtService */
23
    protected $jwtService;
24
    /** @var bool */
25
    protected $checkIp = true;
26
27
    /**
28
     * @param JwtService $jwtService
29
     */
30
    public function __construct(JwtService $jwtService)
31
    {
32
        $this->jwtService = $jwtService;
33
    }
34
35
    /**
36
     * @param bool $checkIp
37
     *
38
     * @return $this
39
     */
40
    public function setCheckIp(bool $checkIp): self
41
    {
42
        $this->checkIp = $checkIp;
43
        return $this;
44
    }
45
46
    /**
47
     * @param string $cookieName
48
     *
49
     * @return $this
50
     */
51
    public function setCookieName(string $cookieName): self
52
    {
53
        $this->cookieName = $cookieName;
54
        return $this;
55
    }
56
57
    /**
58
     * @param string $attr
59
     *
60
     * @return $this
61
     */
62
    public function setIpAttr(string $attr): self
63
    {
64
        $this->ipAttr = $attr;
65
        return $this;
66
    }
67
68
    /**
69
     * @param string $attr
70
     *
71
     * @return $this
72
     */
73
    public function setTokenAttr(string $attr): self
74
    {
75
        $this->tokenAttr = $attr;
76
        return $this;
77
    }
78
79
    /**
80
     * @inheritdoc
81
     * @throws TokenException
82
     */
83
    public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
84
    {
85
        $jwtToken = $this->getTokenFromRequest($request);
86
87
        if (null === $jwtToken) {
88
            return $next->handle($request);
89
        }
90
91
        try {
92
            $token = $this->jwtService->decode($jwtToken);
93
            $this->jwtService->verify($token);
94
95
            $clientIp = $request->getAttribute($this->ipAttr);
96
            $this->checkTokenIp($token, $clientIp);
97
98
            $request = $request->withAttribute($this->tokenAttr, $token);
99
        } catch (\Exception $e) {
100
            throw new TokenException('Bad token', 401, $e);
101
        }
102
103
        return $next->handle($request);
104
    }
105
106
    /**
107
     * @param Token $token
108
     * @param string|null $clientIp
109
     *
110
     * @throws TokenException
111
     */
112
    protected function checkTokenIp(Token $token, string $clientIp = null): void
113
    {
114
        if ($this->checkIp) {
115
            $tokenIp = $this->getIpFromToken($token);
116
117
            if ($tokenIp && $clientIp !== $tokenIp) {
118
                throw new TokenException('Token not valid for this ip');
119
            }
120
        }
121
    }
122
123
    protected function getIpFromToken(Token $token): ?string
124
    {
125
        $tokenIp = $token->getPayload()->findClaimByName('ip');
126
        return $tokenIp !== null ? $tokenIp->getValue() : null;
127
    }
128
129
    /**
130
     * @param ServerRequestInterface $request
131
     *
132
     * @return null|string
133
     */
134
    protected function getTokenFromRequest(ServerRequestInterface $request): ?string
135
    {
136
        return $request->hasHeader('Authorization')
137
            ? $this->getTokenFromBearerHeader($request)
138
            : $this->getTokenFromCookie($request);
139
    }
140
141
    /**
142
     * @param ServerRequestInterface $request
143
     *
144
     * @return null|string
145
     */
146 3
    protected function getTokenFromBearerHeader(ServerRequestInterface $request): ?string
147
    {
148 3
        $header = $request->getHeader('Authorization');
149 3
        list($type, $value) = explode(' ', $header[0]);
150
151 3
        return $type === 'Bearer' ? $value : null;
152
    }
153
154
    /**
155
     * @param ServerRequestInterface $request
156
     *
157
     * @return null|string
158
     */
159 5
    protected function getTokenFromCookie(ServerRequestInterface $request): ?string
160
    {
161 5
        $clientIp = $request->getAttribute($this->ipAttr);
162 5
        $cookieName = $clientIp ? $this->cookieName.'_'.$clientIp : $this->cookieName;
163
164 5
        return $request->getCookieParams()[$cookieName] ?? null;
165
    }
166
}
167