123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- <?php
- namespace Tqdev\PhpCrudApi\Middleware;
-
- use Tqdev\PhpCrudApi\Controller\Responder;
- use Tqdev\PhpCrudApi\Middleware\Base\Middleware;
- use Tqdev\PhpCrudApi\Record\ErrorCode;
- use Tqdev\PhpCrudApi\Request;
- use Tqdev\PhpCrudApi\Response;
-
- class JwtAuthMiddleware extends Middleware
- {
- private function getVerifiedClaims(String $token, int $time, int $leeway, int $ttl, String $secret, array $requirements): array
- {
- $algorithms = array('HS256' => 'sha256', 'HS384' => 'sha384', 'HS512' => 'sha512');
- $token = explode('.', $token);
- if (count($token) < 3) {
- return array();
- }
- $header = json_decode(base64_decode(strtr($token[0], '-_', '+/')), true);
- if (!$secret) {
- return array();
- }
- if ($header['typ'] != 'JWT') {
- return array();
- }
- $algorithm = $header['alg'];
- if (!isset($algorithms[$algorithm])) {
- return array();
- }
- $hmac = $algorithms[$algorithm];
- $signature = bin2hex(base64_decode(strtr($token[2], '-_', '+/')));
- if ($signature != hash_hmac($hmac, "$token[0].$token[1]", $secret)) {
- return array();
- }
- $claims = json_decode(base64_decode(strtr($token[1], '-_', '+/')), true);
- if (!$claims) {
- return array();
- }
- foreach ($requirements as $field => $values) {
- if (!empty($values)) {
- if (!isset($claims[$field]) || !in_array($claims[$field], $values)) {
- return array();
- }
- }
- }
- if (isset($claims['nbf']) && $time + $leeway < $claims['nbf']) {
- return array();
- }
- if (isset($claims['iat']) && $time + $leeway < $claims['iat']) {
- return array();
- }
- if (isset($claims['exp']) && $time - $leeway > $claims['exp']) {
- return array();
- }
- if (isset($claims['iat']) && !isset($claims['exp'])) {
- if ($time - $leeway > $claims['iat'] + $ttl) {
- return array();
- }
- }
- return $claims;
- }
-
- private function getArrayProperty(String $property, String $default): array
- {
- return array_filter(array_map('trim', explode(',', $this->getProperty($property, $default))));
- }
-
- private function getClaims(String $token): array
- {
- $time = (int) $this->getProperty('time', time());
- $leeway = (int) $this->getProperty('leeway', '5');
- $ttl = (int) $this->getProperty('ttl', '30');
- $secret = $this->getProperty('secret', '');
- $requirements = array(
- 'alg' => $this->getArrayProperty('algorithms', ''),
- 'aud' => $this->getArrayProperty('audiences', ''),
- 'iss' => $this->getArrayProperty('issuers', ''),
- );
- if (!$secret) {
- return array();
- }
- return $this->getVerifiedClaims($token, $time, $leeway, $ttl, $secret, $requirements);
- }
-
- private function getAuthorizationToken(Request $request): String
- {
- $parts = explode(' ', trim($request->getHeader('Authorization')), 2);
- if (count($parts) != 2) {
- return '';
- }
- if ($parts[0] != 'Bearer') {
- return '';
- }
- return $parts[1];
- }
-
- public function handle(Request $request): Response
- {
- if (session_status() == PHP_SESSION_NONE) {
- session_start();
- }
- $token = $this->getAuthorizationToken($request);
- if ($token) {
- $claims = $this->getClaims($token);
- $_SESSION['claims'] = $claims;
- if (empty($claims)) {
- return $this->responder->error(ErrorCode::AUTHENTICATION_FAILED, 'JWT');
- }
- }
- if (empty($_SESSION['claims'])) {
- $authenticationMode = $this->getProperty('mode', 'required');
- if ($authenticationMode == 'required') {
- return $this->responder->error(ErrorCode::AUTHENTICATION_REQUIRED, '');
- }
- }
- return $this->next->handle($request);
- }
- }
|