1
This commit is contained in:
@@ -25,7 +25,6 @@ use Kiri\Error\Logger;
|
|||||||
use Kiri\Events\EventProvider;
|
use Kiri\Events\EventProvider;
|
||||||
use Kiri\Exception\InitException;
|
use Kiri\Exception\InitException;
|
||||||
use Kiri\Exception\NotFindClassException;
|
use Kiri\Exception\NotFindClassException;
|
||||||
use Kiri\Jwt\Jwt;
|
|
||||||
use Kiri\Kiri;
|
use Kiri\Kiri;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
use Server\ServerManager;
|
use Server\ServerManager;
|
||||||
@@ -372,16 +371,6 @@ abstract class BaseApplication extends Component
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Jwt
|
|
||||||
* @throws
|
|
||||||
*/
|
|
||||||
public function getJwt(): Jwt
|
|
||||||
{
|
|
||||||
return $this->get('jwt');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Server
|
* @return Server
|
||||||
* @throws
|
* @throws
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
<?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 Http\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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<?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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Kiri\Jwt;
|
|
||||||
|
|
||||||
use Annotation\Inject;
|
|
||||||
use Exception;
|
|
||||||
use Http\Constrict\RequestInterface;
|
|
||||||
use Kiri\Abstracts\Component;
|
|
||||||
use Kiri\Abstracts\Config;
|
|
||||||
use Kiri\Cache\Redis;
|
|
||||||
use Kiri\Core\Json;
|
|
||||||
use Kiri\Exception\ConfigException;
|
|
||||||
use Kiri\Kiri;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class Jwt
|
|
||||||
* @package Kiri\Jwt
|
|
||||||
*/
|
|
||||||
class Jwt extends Component
|
|
||||||
{
|
|
||||||
|
|
||||||
use JwtHelper;
|
|
||||||
|
|
||||||
|
|
||||||
#[Inject(RequestInterface::class)]
|
|
||||||
private RequestInterface $request;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param RequestInterface $request
|
|
||||||
*/
|
|
||||||
public function setRequest(RequestInterface $request): void
|
|
||||||
{
|
|
||||||
$this->request = $request;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws ConfigException
|
|
||||||
* @throws Exception
|
|
||||||
* 'jwt' => [
|
|
||||||
* 'scene' => 'application',
|
|
||||||
* 'timeout' => 7200,
|
|
||||||
* 'encrypt' => '',
|
|
||||||
* 'iv' => '',
|
|
||||||
* 'key' => '',
|
|
||||||
* ]
|
|
||||||
*/
|
|
||||||
public function init()
|
|
||||||
{
|
|
||||||
$this->request = di(RequestInterface::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';
|
|
||||||
}
|
|
||||||
$token = $this->createEncrypt($unionId);
|
|
||||||
if ($this->oos) {
|
|
||||||
$redis = Kiri::getDi()->get(Redis::class);
|
|
||||||
$redis->set('_jwt:token:' . $unionId, $token);
|
|
||||||
$redis->expire('_jwt:token:' . $unionId, $this->timeout);
|
|
||||||
}
|
|
||||||
return $token;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function jwtHeader(): string
|
|
||||||
{
|
|
||||||
return openssl_encrypt(
|
|
||||||
json_encode(['type' => 'openssl', 'encrypt' => $this->encrypt], JSON_UNESCAPED_UNICODE),
|
|
||||||
$this->encrypt,
|
|
||||||
$this->key,
|
|
||||||
0,
|
|
||||||
$this->iv
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $unionId
|
|
||||||
* @return string
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private function jwtBody($unionId): string
|
|
||||||
{
|
|
||||||
$json = json_encode(['unionId' => $unionId, 'createTime' => time(), 'expire_at' => time() + $this->timeout], JSON_UNESCAPED_UNICODE);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
<?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 $iss = 'jwt.service';
|
|
||||||
|
|
||||||
|
|
||||||
private bool $oos = false;
|
|
||||||
|
|
||||||
|
|
||||||
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-----';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getIss(): string
|
|
||||||
{
|
|
||||||
return $this->iss;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $iss
|
|
||||||
*/
|
|
||||||
public function setIss(string $iss): void
|
|
||||||
{
|
|
||||||
$this->iss = $iss;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isOos(): bool
|
|
||||||
{
|
|
||||||
return $this->oos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bool $oos
|
|
||||||
*/
|
|
||||||
public function setOos(bool $oos): void
|
|
||||||
{
|
|
||||||
$this->oos = $oos;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -229,6 +229,15 @@ class Kiri
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Container
|
||||||
|
*/
|
||||||
|
public static function di(): Container
|
||||||
|
{
|
||||||
|
return static::$container;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $workerId
|
* @param $workerId
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
|||||||
Reference in New Issue
Block a user