Files
kiri-core/System/Jwt/Jwt.php
T

191 lines
3.8 KiB
PHP
Raw Normal View History

2020-09-01 13:36:57 +08:00
<?php
2020-10-29 18:17:25 +08:00
declare(strict_types=1);
2020-09-01 13:36:57 +08:00
2021-08-11 01:04:57 +08:00
namespace Kiri\Jwt;
2020-09-01 13:36:57 +08:00
use Exception;
2021-08-11 01:04:57 +08:00
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Core\Json;
use Kiri\Exception\ConfigException;
2021-08-11 11:31:15 +08:00
use Server\Constrict\Request;
2020-09-01 13:36:57 +08:00
2020-12-17 14:09:14 +08:00
/**
* Class Jwt
2021-08-11 01:04:57 +08:00
* @package Kiri\Jwt
2020-12-17 14:09:14 +08:00
*/
2020-09-01 13:36:57 +08:00
class Jwt extends Component
{
2021-08-06 16:54:17 +08:00
use JwtHelper;
2020-09-01 13:36:57 +08:00
2021-08-06 16:54:17 +08:00
private Request $request;
2020-09-01 13:36:57 +08:00
2020-09-08 10:45:39 +08:00
2021-07-08 19:16:27 +08:00
/**
* @throws ConfigException
2021-07-13 17:15:07 +08:00
* @throws Exception
2021-08-11 14:06:42 +08:00
* 'jwt' => [
* 'scene' => 'application',
* 'timeout' => 7200,
* 'encrypt' => '',
* 'iv' => '',
* 'key' => '',
* ]
2021-07-08 19:16:27 +08:00
*/
public function init()
{
2021-08-06 17:02:33 +08:00
$this->request = di(Request::class);
2021-08-11 14:06:42 +08:00
2021-07-08 19:16:27 +08:00
$this->public = Config::get('ssl.public', $this->public);
$this->private = Config::get('ssl.private', $this->private);
2021-08-11 14:07:58 +08:00
$this->timeout = Config::get('jwt.timeout', 7200);
2021-08-11 14:06:42 +08:00
$jwt = Config::get('jwt', []);
if ($jwt) {
$this->setScene($jwt['scene'] ?? 'application');
$this->setKey($jwt['key'] ?? get_called_class());
2021-08-11 14:19:59 +08:00
$length = openssl_cipher_iv_length($this->encrypt);
if ($length > 0) {
$defaultIv = openssl_random_pseudo_bytes($length);
$this->setIv($jwt['iv'] ?? $defaultIv);
}
2021-08-11 14:06:42 +08:00
}
2021-07-08 19:16:27 +08:00
}
/**
* @param int $unionId
*
2021-08-06 16:54:17 +08:00
* @return string
2021-07-08 19:16:27 +08:00
* @throws Exception
*/
2021-08-06 16:54:17 +08:00
public function create(int $unionId): string
2021-07-08 19:16:27 +08:00
{
$this->user = $unionId;
$this->config['time'] = time();
2021-08-06 16:54:17 +08:00
$this->data = $this->request->getHeaders();
2021-07-08 19:16:27 +08:00
if (!isset($this->data['source'])) {
$this->data['source'] = 'browser';
}
return $this->createEncrypt($unionId);
}
/**
2021-08-06 16:54:17 +08:00
* @return string
2021-07-08 19:16:27 +08:00
*/
2021-08-06 16:54:17 +08:00
private function jwtHeader(): string
2021-07-08 19:16:27 +08:00
{
2021-08-11 14:06:42 +08:00
$string = openssl_encrypt(
json_encode(['type' => 'openssl', 'encrypt' => $this->encrypt]),
$this->encrypt,
$this->key,
0,
$this->iv
);
return str_replace('=', '', $string);
2021-07-08 19:16:27 +08:00
}
2021-04-04 03:01:12 +08:00
2021-06-29 10:57:39 +08:00
/**
2021-08-06 16:54:17 +08:00
* @param $unionId
* @return string
2021-07-08 19:16:27 +08:00
* @throws Exception
*/
2021-08-06 16:54:17 +08:00
private function jwtBody($unionId): string
2021-07-08 19:16:27 +08:00
{
2021-08-06 16:54:17 +08:00
$json = json_encode(['unionId' => $unionId, 'createTime' => time(), 'loginIp' => request()->getIp(), 'expire_at' => time() + $this->timeout]);
openssl_private_encrypt($json, $encode, $this->private);
return base64_encode($encode);
2021-07-08 19:16:27 +08:00
}
/**
2021-08-06 16:54:17 +08:00
* @param $unionId
2021-07-08 19:16:27 +08:00
* @return string
* @throws Exception
*/
2021-08-06 16:54:17 +08:00
private function createEncrypt($unionId): string
2021-07-08 19:16:27 +08:00
{
2021-08-06 16:54:17 +08:00
$params[] = $this->jwtHeader();
$params[] = $this->jwtBody($unionId);
2021-07-08 19:16:27 +08:00
2021-08-11 14:41:43 +08:00
$params[] = hash('sha256', $params[0] . $params[1]);
2021-08-06 16:54:17 +08:00
return implode('.', $params);
2021-07-08 19:16:27 +08:00
}
/**
2021-08-06 16:54:17 +08:00
* @param $token
2021-08-06 17:46:35 +08:00
* @return string|int
2021-08-06 16:54:17 +08:00
* @throws JWTAuthTokenException
2021-07-08 19:16:27 +08:00
*/
2021-08-06 17:46:35 +08:00
public function getUnionId($token): string|int
2021-07-08 19:16:27 +08:00
{
2021-08-06 18:14:27 +08:00
$unpack = $this->unpack($token);
if (!$this->_validator($unpack)) {
throw new JWTAuthTokenException('JWT certificate has expired.');
}
return $unpack['unionId'];
2021-07-08 19:16:27 +08:00
}
/**
2021-08-06 16:54:17 +08:00
* @param $token
2021-07-08 19:16:27 +08:00
* @return bool
2021-08-06 16:54:17 +08:00
* @throws JWTAuthTokenException
2021-07-08 19:16:27 +08:00
*/
2021-08-06 16:54:17 +08:00
public function validator($token): bool
2021-07-08 19:16:27 +08:00
{
2021-08-06 18:14:27 +08:00
return $this->_validator($this->unpack($token));
}
/**
* @param $unpack
* @return bool
*/
private function _validator($unpack): bool
{
2021-08-06 16:54:17 +08:00
if ($unpack['expire_at'] < time()) {
return false;
2021-07-08 19:16:27 +08:00
}
2021-08-06 16:54:17 +08:00
return true;
2021-07-08 19:16:27 +08:00
}
/**
2021-08-06 16:54:17 +08:00
* @param $token
* @return string
* @throws JWTAuthTokenException
2021-07-08 19:16:27 +08:00
* @throws Exception
*/
2021-08-06 16:54:17 +08:00
public function refresh($token): string
2021-07-08 19:16:27 +08:00
{
2021-08-06 16:54:17 +08:00
return $this->create($this->unpack($token)['unionId']);
2021-07-08 19:16:27 +08:00
}
/**
2021-08-06 16:54:17 +08:00
* @param string $token
2021-07-08 19:16:27 +08:00
* @return mixed
2021-08-06 16:54:17 +08:00
* @throws JWTAuthTokenException
2021-07-08 19:16:27 +08:00
*/
2021-08-06 17:41:04 +08:00
private function unpack(string $token): array
2021-07-08 19:16:27 +08:00
{
2021-08-06 16:54:17 +08:00
if (count($explode = explode('.', $token)) != 3) {
throw new JWTAuthTokenException('JWT Voucher Format Error.');
2021-07-08 19:16:27 +08:00
}
2021-08-11 14:41:43 +08:00
if (hash('sha256', $explode[0] . $explode[1]) != $explode[2]) {
2021-08-06 16:54:17 +08:00
throw new JWTAuthTokenException('JWT Sign Validator Fail.');
2021-07-08 19:16:27 +08:00
}
2021-08-06 16:54:17 +08:00
if (!openssl_public_decrypt(base64_decode($explode[1]), $decode, $this->public)) {
throw new JWTAuthTokenException('JWT Voucher Unpack Error.');
2021-07-08 19:16:27 +08:00
}
2021-08-06 16:54:17 +08:00
return Json::decode($decode, true);
2021-07-08 19:16:27 +08:00
}
2020-09-01 13:36:57 +08:00
}