This commit is contained in:
2021-09-24 17:27:25 +08:00
parent dbc30827f8
commit 8a0858fbd7
72 changed files with 1 additions and 1 deletions
+57
View File
@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Kiri\Jwt;
use Annotation\Inject;
use Exception;
use Http\Message\ServerRequest;
use Kiri\Kiri;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Server\Constrict\ResponseInterface;
/**
* Class CoreMiddleware
* @package Kiri\Kiri\Route
* 跨域中间件
*/
class JWTAuthMiddleware implements MiddlewareInterface
{
/** @var int */
public int $zOrder = 0;
#[Inject(ResponseInterface::class)]
public ResponseInterface $response;
/**
* @param ServerRequest $request
* @param RequestHandlerInterface $handler
* @return \Psr\Http\Message\ResponseInterface
* @throws Exception
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): \Psr\Http\Message\ResponseInterface
{
$authorization = $request->getHeaderLine('Authorization');
if (empty($authorization)) {
return $this->response->json(['code' => 401, 'JWT voucher cannot be empty.']);
}
if (!str_starts_with($authorization, 'Bearer ')) {
return $this->response->json(['code' => 401, 'JWT Voucher Format Error.']);
}
$authorization = str_replace('Bearer ', '', $authorization);
$jwt = Kiri::app()->getJwt();
if (!$jwt->validator($authorization)) {
return $this->response->json(['code' => 401, 'JWT Validator fail.']);
}
return $handler->handle($request);
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace Kiri\Jwt;
use JetBrains\PhpStorm\Pure;
use Throwable;
/**
*
*/
class JWTAuthTokenException extends \Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
#[Pure] public function __construct($message = "", $code = 4001, Throwable $previous = null)
{
parent::__construct($message, 4001, $previous);
}
}
+201
View File
@@ -0,0 +1,201 @@
<?php
declare(strict_types=1);
namespace Kiri\Jwt;
use Annotation\Inject;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Core\Json;
use Kiri\Exception\ConfigException;
use Server\Constrict\Request;
/**
* Class Jwt
* @package Kiri\Jwt
*/
class Jwt extends Component
{
use JwtHelper;
#[Inject(Request::class)]
private Request $request;
/**
* @param Request $request
*/
public function setRequest(Request $request): void
{
$this->request = $request;
}
/**
* @throws ConfigException
* @throws Exception
* 'jwt' => [
* 'scene' => 'application',
* 'timeout' => 7200,
* 'encrypt' => '',
* 'iv' => '',
* 'key' => '',
* ]
*/
public function init()
{
$this->request = di(Request::class);
$this->public = Config::get('ssl.public', $this->public);
$this->private = Config::get('ssl.private', $this->private);
$this->timeout = Config::get('jwt.timeout', 7200);
$jwt = Config::get('jwt', []);
if ($jwt) {
$this->setScene($jwt['scene'] ?? 'application');
$this->setKey($jwt['key'] ?? get_called_class());
$length = openssl_cipher_iv_length($this->encrypt);
if ($length > 0) {
$defaultIv = openssl_random_pseudo_bytes($length);
$this->setIv($jwt['iv'] ?? $defaultIv);
}
}
}
/**
* @param int $unionId
*
* @return string
* @throws Exception
*/
public function create(int $unionId): string
{
$this->user = $unionId;
$this->config['time'] = time();
$this->data = $this->request->getHeaders();
if (!isset($this->data['source'])) {
$this->data['source'] = 'browser';
}
return $this->createEncrypt($unionId);
}
/**
* @return string
*/
private function jwtHeader(): string
{
$string = openssl_encrypt(
json_encode(['type' => 'openssl', 'encrypt' => $this->encrypt]),
$this->encrypt,
$this->key,
0,
$this->iv
);
return str_replace('=', '', $string);
}
/**
* @param $unionId
* @return string
* @throws Exception
*/
private function jwtBody($unionId): string
{
$json = json_encode(['unionId' => $unionId, 'createTime' => time(), 'expire_at' => time() + $this->timeout]);
openssl_private_encrypt($json, $encode, $this->private);
return base64_encode($encode);
}
/**
* @param $unionId
* @return string
* @throws Exception
*/
private function createEncrypt($unionId): string
{
$params[] = $this->jwtHeader();
$params[] = $this->jwtBody($unionId);
$params[] = hash('sha256', $params[0] . $params[1]);
return implode('.', $params);
}
/**
* @param $token
* @return string|int
* @throws JWTAuthTokenException
*/
public function getUnionId($token): string|int
{
$unpack = $this->unpack($token);
if (!$this->_validator($unpack)) {
throw new JWTAuthTokenException('JWT certificate has expired.');
}
return $unpack['unionId'];
}
/**
* @param $token
* @return bool
* @throws JWTAuthTokenException
*/
public function validator($token): bool
{
return $this->_validator($this->unpack($token));
}
/**
* @param $unpack
* @return bool
*/
private function _validator($unpack): bool
{
if ($unpack['expire_at'] < time()) {
return false;
}
return true;
}
/**
* @param $token
* @return string
* @throws JWTAuthTokenException
* @throws Exception
*/
public function refresh($token): string
{
return $this->create($this->unpack($token)['unionId']);
}
/**
* @param string $token
* @return mixed
* @throws JWTAuthTokenException
*/
private function unpack(string $token): array
{
if (count($explode = explode('.', $token)) != 3) {
throw new JWTAuthTokenException('JWT Voucher Format Error.');
}
if (hash('sha256', $explode[0] . $explode[1]) != $explode[2]) {
throw new JWTAuthTokenException('JWT Sign Validator Fail.');
}
if (!openssl_public_decrypt(base64_decode($explode[1]), $decode, $this->public)) {
throw new JWTAuthTokenException('JWT Voucher Unpack Error.');
}
return Json::decode($decode, true);
}
}
+134
View File
@@ -0,0 +1,134 @@
<?php
namespace Kiri\Jwt;
trait JwtHelper
{
/** @var int $user */
private int $user;
private array $data;
private array $source = ['browser', 'android', 'iphone', 'pc', 'mingame'];
private array $config = ['token' => ''];
private ?int $timeout = 7200;
private string $key = 'www.xshucai.com';
private string $secret = '';
private string $scene = 'default';
private string $encrypt = 'aes-128-ecb';
private string $iv = '';
private ?string $public = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6BuML3gtLGde7QKNuNST
UCB9gdHC7XIpOc7Wx2I64Esj3UxWHTgp3URj0ge8zpy7A3FfBdppR7d1nwoD6Xad
jqfjEWpTy4WwGYsOfH0tFl3wAmse0lebF4NFsS9pzrikQT6c9qsVm88pCjvg4i5t
WhTMEnpTFDYoDR0KXlLXltQMudBBUHFaVwP0wKJ/cGX7R1Mrv35K4MXwQFOuGZkP
hsp2rO9x5LjtSKIXbexy7WhUu6QMjD/XzgsXr9UF+ExYmBGXRVWgNFLMkiaCZ2Uz
WlQhpQrA5/wKd76dCzjvqw9M32OiZl2lCKT73cV8GUvt7BNsM1SiPhqfY7nhO6y3
cwIDAQAB
-----END PUBLIC KEY-----';
private ?string $private = '-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA6BuML3gtLGde7QKNuNSTUCB9gdHC7XIpOc7Wx2I64Esj3UxW
HTgp3URj0ge8zpy7A3FfBdppR7d1nwoD6XadjqfjEWpTy4WwGYsOfH0tFl3wAmse
0lebF4NFsS9pzrikQT6c9qsVm88pCjvg4i5tWhTMEnpTFDYoDR0KXlLXltQMudBB
UHFaVwP0wKJ/cGX7R1Mrv35K4MXwQFOuGZkPhsp2rO9x5LjtSKIXbexy7WhUu6QM
jD/XzgsXr9UF+ExYmBGXRVWgNFLMkiaCZ2UzWlQhpQrA5/wKd76dCzjvqw9M32Oi
Zl2lCKT73cV8GUvt7BNsM1SiPhqfY7nhO6y3cwIDAQABAoIBADPihJHP8XktmmCs
43Vfv5Z3zNaKR2LA1Eph3E0xviuJYHkFqXJarbESqqW2qRQeoQeB/lXWnxYzAo4M
tRcpNss+6FlqRVUHi3gKR7C4Yq3PTemcfIVUpAy7gYa8LJDTYZRcJMZXNDtiMbBh
9kFZU4SBhaTTx2KLQKS9yyWOqzbBvyLXN+1+Wy477M9+MXXTKw79dO+pML6cR0yl
pNfVR5FX5L/GB5vOtQB/Aqg/CKT8NC5MzWPnKY+TPCCHZyoZuB9dLDuWOlqsN4QX
Y4B8fFca5yRwzHra5aGoqdaT/zGctt+I6V/f/KNQCo36f9LPxeXg1+FHvvtTj5WZ
N8CGPzECgYEA9R7lRMXzrHE4rK0DhxQXIFbIKKtxrimqZQdbwOUeYYD2R6CDSItK
z88RSYElmd6wiS7fYIaheXNqJ8Yu6SQFBF/yshBwjQVl9NJG94LJlgx1XnVZEju6
OZjMUOhHXBymtXnLo16pDRl8odc4MFLRH25/vLtwChUr+Qoyt54GzFUCgYEA8mjL
jdh94JAmcdnDXsKgjNOGyNWGDVvWoFmy8lEQsMXY1JJnEd3YfDM2prmv3vaoiXzi
YkSETl6ZUtJqh78MnHCBY1vI6EAcKQAF/kvP2TataRCXNcGNQwn2mtq+B+heTta6
Di8jjAdmdUAYHbmOQryBudiRYG7JEF038elzvKcCgYEAq81ByFguGBkrLev94vkz
1Fi+5bJ0dSuC4Fit+J8eEhz/gOiB26C1iL2LUkeQgS5R8XTG37K9DpDUQJhpXMMA
OTa+tgtLt6um8FdJokUq4V5ODSyWh28RcTklSzfifC8gsWVyU0kPl7zbW9uq6EPD
ixI5uaBuQMLiFSUOsx+xiBkCgYEAtqXHWeVZUy7KCNavomK7XeCzmfdovgAIw2FS
t8nk7YzlR6XYC1pAl7Ru5Ujb/v+TFaUHXkuJ9RLKK+Fna0jEU8thcl/iDTzg+vON
kIHG5j+Qga2CgXqI2Y5URXGz5XlsNbMNFUrnWcbpqEbW5O6/BgHLLSDEyQgwbygN
0zS3g9kCgYEAhssb7kOljdIul4lY5MXc67Zf1dp6S2bucLOxsG6cRW07b3pBz7QF
5aPE7ZwnkzTnA4HuGGauKj+qKGAR7ve55XClAq/XipiVFrjwV/t3LC6j5DoqTJYR
mlAZUEjsoaT9vjvjGTxl3uCm0TX5KTgtSJIt2kA1tYVjQef+/iZTHxY=
-----END RSA PRIVATE KEY-----';
/**
* @param string $publicKey
*/
public function setPublic(string $publicKey)
{
$this->public = $publicKey;
}
/**
* @param int $timeout
*/
public function setTimeout(int $timeout)
{
$this->timeout = $timeout;
}
public function setScene(string $scene)
{
$this->scene = $scene;
}
/**
* @param string $timeout
*/
public function setKey(string $timeout)
{
$this->key = $timeout;
}
/**
* @param string $privateKey
*/
public function setPrivate(string $privateKey)
{
$this->private = $privateKey;
}
/**
* @param string $privateKey
*/
public function setIv(string $privateKey)
{
$this->iv = $privateKey;
}
/**
* @param string $privateKey
*/
public function setEncrypt(string $privateKey)
{
$this->encrypt = $privateKey;
}
}