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
|
|
|
|
|
|
|
|
namespace Snowflake\Jwt;
|
|
|
|
|
|
|
|
|
|
use Exception;
|
2021-08-06 16:54:17 +08:00
|
|
|
use Server\Constrict\Request;
|
2021-07-08 19:16:27 +08:00
|
|
|
use Snowflake\Abstracts\Component;
|
2020-09-08 10:45:39 +08:00
|
|
|
use Snowflake\Abstracts\Config;
|
2021-07-09 10:41:31 +08:00
|
|
|
use Snowflake\Core\Json;
|
2020-09-08 10:45:39 +08:00
|
|
|
use Snowflake\Exception\ConfigException;
|
2020-09-01 13:36:57 +08:00
|
|
|
|
2020-12-17 14:09:14 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Class Jwt
|
|
|
|
|
* @package Snowflake\Jwt
|
|
|
|
|
*/
|
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-07-08 19:16:27 +08:00
|
|
|
*/
|
|
|
|
|
public function init()
|
|
|
|
|
{
|
2021-08-06 17:02:33 +08:00
|
|
|
$this->request = di(Request::class);
|
2021-07-08 19:16:27 +08:00
|
|
|
if (!Config::has('ssl.public') || !Config::has('ssl.private')) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$this->public = Config::get('ssl.public', $this->public);
|
|
|
|
|
$this->private = Config::get('ssl.private', $this->private);
|
|
|
|
|
$this->timeout = Config::get('ssl.timeout', 7200);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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-06 16:54:17 +08:00
|
|
|
return base64_encode(json_encode(['type' => 'openssl', 'encrypt' => $this->encrypt]));
|
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-06 16:54:17 +08:00
|
|
|
$params[] = hash($this->encrypt, $params[0] . $params[1]);
|
|
|
|
|
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-06 16:54:17 +08:00
|
|
|
if (hash($this->encrypt, $explode[0] . $explode[1]) != $explode[2]) {
|
|
|
|
|
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
|
|
|
|
|
|
|
|
}
|