From d531b5e84777eff8429b668c1c7fc4e022338ce6 Mon Sep 17 00:00:00 2001 From: xiaodai <1318762926@qq.com> Date: Mon, 4 Aug 2025 11:03:49 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=9B=AA=E8=8A=B1?= =?UTF-8?q?=E7=AE=97=E6=B3=95=E6=97=B6=E9=97=B4=E5=9B=9E=E6=8B=A8=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=B9=B6=E5=8F=91=E7=94=9F=E6=88=90ID?= =?UTF-8?q?=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/core/utils/Snowflake.php | 182 ++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 server/core/utils/Snowflake.php diff --git a/server/core/utils/Snowflake.php b/server/core/utils/Snowflake.php new file mode 100644 index 0000000..4105d37 --- /dev/null +++ b/server/core/utils/Snowflake.php @@ -0,0 +1,182 @@ + self::MAX_WORKER_ID || $workerId < 0) { + throw new InvalidArgumentException("Worker ID can't be greater than " . self::MAX_WORKER_ID . " or less than 0"); + } + if ($dataCenterId > self::MAX_DATA_CENTER_ID || $dataCenterId < 0) { + throw new InvalidArgumentException("Data Center ID can't be greater than " . self::MAX_DATA_CENTER_ID . " or less than 0"); + } + + $this->workerId = $workerId; + $this->dataCenterId = $dataCenterId; + $this->enableSleepWait = $enableSleepWait; + $this->useHighPerfClock = $useHighPerfClock; + $this->bufferSize = max(1, min(100, $bufferSize)); + } + + /** + * 获取下一个唯一 ID + * + * @return string + * @throws RuntimeException + */ + /** + * 批量生成ID (减少锁竞争) + */ + public function nextIds(int $count = 1): array + { + $count = max(1, min(100, $count)); + $ids = []; + while ($count-- > 0) { + $ids[] = $this->generateId(); + } + return $ids; + } + + public function nextId(): string + { + if (!empty($this->idBuffer)) { + return array_shift($this->idBuffer); + } + $this->idBuffer = $this->nextIds($this->bufferSize); + return $this->nextId(); + } + + private function generateId(): string + { + $timestamp = $this->timeGen(); + + if ($timestamp < $this->lastTimestamp - $this->timeBackwardsTolerance) { + throw new RuntimeException("时钟回拨超过容忍范围: " . ($this->lastTimestamp - $timestamp) . "ms"); + } + + if ($timestamp == $this->lastTimestamp) { + $this->sequence = ($this->sequence + 1) & self::SEQUENCE_MASK; + if ($this->sequence === 0) { + // 等待下一毫秒 + $timestamp = $this->tilNextMillis($this->lastTimestamp); + } + } else { + $this->sequence = 0; + } + + $this->lastTimestamp = $timestamp; + + $timestampDelta = $timestamp - self::EPOCH; + $workerIdShift = self::SEQUENCE_BITS; + $dataCenterIdShift = self::WORKER_ID_BITS + self::SEQUENCE_BITS; + $timestampShift = self::DATA_CENTER_ID_BITS + self::WORKER_ID_BITS + self::SEQUENCE_BITS; + + $id = ($timestampDelta << $timestampShift) + | ($this->dataCenterId << $dataCenterIdShift) + | ($this->workerId << $workerIdShift) + | $this->sequence; + + return (string)$id; + } + + /** + * 解析Snowflake ID + */ + public static function parseId(string $id): array + { + $id = (int)$id; + return [ + 'timestamp' => ($id >> 22) + self::EPOCH, + 'dataCenterId' => ($id >> 17) & 0x1F, + 'workerId' => ($id >> 12) & 0x1F, + 'sequence' => $id & 0xFFF, + 'datetime' => date('Y-m-d H:i:s', (($id >> 22) + self::EPOCH) / 1000) + ]; + } + + /** + * 返回固定长度的 ID(左补 0) + * + * @param int $length + * @return string + */ + public function nextFixedLengthId(int $length): string + { + return str_pad($this->nextId(), $length, '0', STR_PAD_LEFT); + } + + /** + * 获取当前时间戳(毫秒) + * + * @return int + */ + private function timeGen(): int + { + if ($this->useHighPerfClock && function_exists('hrtime')) { + return (int)(hrtime(true) / 1e6); // 纳秒转毫秒 + } + return (int)(microtime(true) * 1000); + } + + /** + * 等待下一毫秒 + * + * @param int $lastTimestamp + * @return int + */ + private function tilNextMillis(int $lastTimestamp): int + { + $timestamp = $this->timeGen(); + if ($this->enableSleepWait) { + $sleepUs = ($lastTimestamp - $timestamp + 1) * 1000; + usleep(max(100, $sleepUs)); // 最小休眠100us + return $this->timeGen(); + } + + // 兼容模式:忙等待 + while ($timestamp <= $lastTimestamp) { + $timestamp = $this->timeGen(); + } + return $timestamp; + } +} -- Gitee From 57432eff4e44c2f65184beac87c7662fba7527a3 Mon Sep 17 00:00:00 2001 From: xiaodai <1318762926@qq.com> Date: Wed, 6 Aug 2025 10:41:07 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=A4=84=E7=90=86token=E9=BB=91=E5=90=8D?= =?UTF-8?q?=E5=8D=95=E5=BC=82=E5=B8=B8=E6=8A=9B=E5=87=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/app/functions.php | 34 +++++++++++-------- server/app/middleware/AuthTokenMiddleware.php | 11 ++++-- .../app/middleware/PermissionMiddleware.php | 11 ++++-- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/server/app/functions.php b/server/app/functions.php index e8fbac0..708afe6 100644 --- a/server/app/functions.php +++ b/server/app/functions.php @@ -18,24 +18,28 @@ use support\Container; */ function getCurrentUser(bool $fullInfo = false, bool $refresh = false): mixed { - // 1. 验证请求和授权令牌 - $token = resolveAuthorizationToken(); - if ($token === null) { - return null; - } + try { + // 1. 验证请求和授权令牌 + $token = resolveAuthorizationToken(); + if ($token === null) { + return null; + } - // 2. 获取当前用户ID - $userId = JwtToken::getCurrentId(); - if ($userId === null) { - return null; - } + // 2. 获取当前用户ID + $userId = JwtToken::getCurrentId(); + if ($userId === null) { + return null; + } - // 3. 根据参数返回相应数据 - if ($refresh) { - return $fullInfo ? JwtToken::getUser() : $userId; - } + // 3. 根据参数返回相应数据 + if ($refresh) { + return $fullInfo ? JwtToken::getUser() : $userId; + } - return $fullInfo ? JwtToken::getExtend() : $userId; + return $fullInfo ? JwtToken::getExtend() : $userId; + } catch (\Exception $e) { + return null; + } } function resolveAuthorizationToken(): ?string diff --git a/server/app/middleware/AuthTokenMiddleware.php b/server/app/middleware/AuthTokenMiddleware.php index 02a64a8..27de2ca 100644 --- a/server/app/middleware/AuthTokenMiddleware.php +++ b/server/app/middleware/AuthTokenMiddleware.php @@ -14,6 +14,7 @@ namespace app\middleware; use core\jwt\JwtToken; use core\exception\handler\UnauthorizedHttpException; +use core\utils\Json; use Webman\Http\Request; use Webman\Http\Response; use Webman\MiddlewareInterface; @@ -49,9 +50,13 @@ class AuthTokenMiddleware implements MiddlewareInterface return $handler($request); } - $userId = JwtToken::getCurrentId(); - if (0 === $userId) { - throw new UnauthorizedHttpException(); + try { + $userId = JwtToken::getCurrentId(); + if (0 === $userId) { + throw new UnauthorizedHttpException(); + } + }catch (\Exception $e){ + return Json::fail($e->getMessage(), [], 401); } return $handler($request); } diff --git a/server/app/middleware/PermissionMiddleware.php b/server/app/middleware/PermissionMiddleware.php index ecb88e6..65a98ce 100644 --- a/server/app/middleware/PermissionMiddleware.php +++ b/server/app/middleware/PermissionMiddleware.php @@ -20,6 +20,7 @@ use core\enum\system\PolicyPrefix; use core\exception\handler\ForbiddenHttpException; use core\exception\handler\UnauthorizedHttpException; use core\jwt\JwtToken; +use core\utils\Json; use Webman\Http\Request; use Webman\Http\Response; use Webman\MiddlewareInterface; @@ -63,9 +64,13 @@ class PermissionMiddleware implements MiddlewareInterface return $handler($request); } - $userId = JwtToken::getCurrentId(); - if ($userId === 0) { - throw new UnauthorizedHttpException(); + try { + $userId = JwtToken::getCurrentId(); + if (0 === $userId) { + throw new UnauthorizedHttpException(); + } + }catch (\Exception $e){ + return Json::fail($e->getMessage(), [], 401); } $userData = JwtToken::getExtend(); // 顶级管理员直接跳过权限验证 -- Gitee From 21c69feef18d632e416fe2ba0e7828c1707d2243 Mon Sep 17 00:00:00 2001 From: xiaodai <1318762926@qq.com> Date: Wed, 6 Aug 2025 12:16:10 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=A4=84=E7=90=86=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E8=A7=92=E8=89=B2=E4=B8=8D=E5=9B=9E=E6=98=BE?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/app/common/dao/system/SysAdminDao.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/app/common/dao/system/SysAdminDao.php b/server/app/common/dao/system/SysAdminDao.php index 029930c..89ce32b 100644 --- a/server/app/common/dao/system/SysAdminDao.php +++ b/server/app/common/dao/system/SysAdminDao.php @@ -201,7 +201,7 @@ class SysAdminDao extends BaseDao { $result = $this->getModel() ->where('id', $id) - ->with(['depts', 'posts', 'casbin.roles',]) + ->with(['depts', 'posts', 'casbin.roles','roles']) ->first() ->makeHidden(['password', 'backend_setting']); -- Gitee From eea2ac8867da8ca432f9a91da107f50962f1fa09 Mon Sep 17 00:00:00 2001 From: xiaodai <1318762926@qq.com> Date: Wed, 6 Aug 2025 13:40:22 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E9=9B=AA=E8=8A=B1=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/core/utils/Snowflake.php | 182 -------------------------------- 1 file changed, 182 deletions(-) delete mode 100644 server/core/utils/Snowflake.php diff --git a/server/core/utils/Snowflake.php b/server/core/utils/Snowflake.php deleted file mode 100644 index 4105d37..0000000 --- a/server/core/utils/Snowflake.php +++ /dev/null @@ -1,182 +0,0 @@ - self::MAX_WORKER_ID || $workerId < 0) { - throw new InvalidArgumentException("Worker ID can't be greater than " . self::MAX_WORKER_ID . " or less than 0"); - } - if ($dataCenterId > self::MAX_DATA_CENTER_ID || $dataCenterId < 0) { - throw new InvalidArgumentException("Data Center ID can't be greater than " . self::MAX_DATA_CENTER_ID . " or less than 0"); - } - - $this->workerId = $workerId; - $this->dataCenterId = $dataCenterId; - $this->enableSleepWait = $enableSleepWait; - $this->useHighPerfClock = $useHighPerfClock; - $this->bufferSize = max(1, min(100, $bufferSize)); - } - - /** - * 获取下一个唯一 ID - * - * @return string - * @throws RuntimeException - */ - /** - * 批量生成ID (减少锁竞争) - */ - public function nextIds(int $count = 1): array - { - $count = max(1, min(100, $count)); - $ids = []; - while ($count-- > 0) { - $ids[] = $this->generateId(); - } - return $ids; - } - - public function nextId(): string - { - if (!empty($this->idBuffer)) { - return array_shift($this->idBuffer); - } - $this->idBuffer = $this->nextIds($this->bufferSize); - return $this->nextId(); - } - - private function generateId(): string - { - $timestamp = $this->timeGen(); - - if ($timestamp < $this->lastTimestamp - $this->timeBackwardsTolerance) { - throw new RuntimeException("时钟回拨超过容忍范围: " . ($this->lastTimestamp - $timestamp) . "ms"); - } - - if ($timestamp == $this->lastTimestamp) { - $this->sequence = ($this->sequence + 1) & self::SEQUENCE_MASK; - if ($this->sequence === 0) { - // 等待下一毫秒 - $timestamp = $this->tilNextMillis($this->lastTimestamp); - } - } else { - $this->sequence = 0; - } - - $this->lastTimestamp = $timestamp; - - $timestampDelta = $timestamp - self::EPOCH; - $workerIdShift = self::SEQUENCE_BITS; - $dataCenterIdShift = self::WORKER_ID_BITS + self::SEQUENCE_BITS; - $timestampShift = self::DATA_CENTER_ID_BITS + self::WORKER_ID_BITS + self::SEQUENCE_BITS; - - $id = ($timestampDelta << $timestampShift) - | ($this->dataCenterId << $dataCenterIdShift) - | ($this->workerId << $workerIdShift) - | $this->sequence; - - return (string)$id; - } - - /** - * 解析Snowflake ID - */ - public static function parseId(string $id): array - { - $id = (int)$id; - return [ - 'timestamp' => ($id >> 22) + self::EPOCH, - 'dataCenterId' => ($id >> 17) & 0x1F, - 'workerId' => ($id >> 12) & 0x1F, - 'sequence' => $id & 0xFFF, - 'datetime' => date('Y-m-d H:i:s', (($id >> 22) + self::EPOCH) / 1000) - ]; - } - - /** - * 返回固定长度的 ID(左补 0) - * - * @param int $length - * @return string - */ - public function nextFixedLengthId(int $length): string - { - return str_pad($this->nextId(), $length, '0', STR_PAD_LEFT); - } - - /** - * 获取当前时间戳(毫秒) - * - * @return int - */ - private function timeGen(): int - { - if ($this->useHighPerfClock && function_exists('hrtime')) { - return (int)(hrtime(true) / 1e6); // 纳秒转毫秒 - } - return (int)(microtime(true) * 1000); - } - - /** - * 等待下一毫秒 - * - * @param int $lastTimestamp - * @return int - */ - private function tilNextMillis(int $lastTimestamp): int - { - $timestamp = $this->timeGen(); - if ($this->enableSleepWait) { - $sleepUs = ($lastTimestamp - $timestamp + 1) * 1000; - usleep(max(100, $sleepUs)); // 最小休眠100us - return $this->timeGen(); - } - - // 兼容模式:忙等待 - while ($timestamp <= $lastTimestamp) { - $timestamp = $this->timeGen(); - } - return $timestamp; - } -} -- Gitee