重构 monorepo 并完善网页端订阅与首页体验

- 迁移为 frontend-web、frontend-electron、backend-web 与 docker 部署结构
- 网页端:订阅门禁二次弹窗、套餐/支付组件化、顶栏分组对齐
- 首页:最近文件与模板库布局优化,缩略图对齐,下载与删除操作
- 新增管理后台、支付与云端文件 API,更新 README 与项目规范

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
24kycj
2026-06-08 18:17:39 +08:00
parent 5814b7bc0e
commit 88c6ce8ccc
511 changed files with 189528 additions and 22804 deletions
+83
View File
@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace Soon\Api\Core;
/**
* HS256 JWT 工具。iss = site.base_url,签发与解码双向校验。
*/
final class Jwt
{
public static function issuer(): string
{
return (string)Config::get('site.base_url', 'soondesign');
}
public static function secret(): string
{
return (string)Config::get('app.jwt_secret', 'change-me-in-prod');
}
public static function ttl(): int
{
return (int)Config::get('app.jwt_ttl', 3600);
}
public static function refreshTtl(): int
{
return (int)Config::get('app.jwt_refresh_ttl', 2592000);
}
public static function encode(array $claims): string
{
$header = ['alg' => 'HS256', 'typ' => 'JWT'];
$payload = array_merge([
'iss' => self::issuer(),
'iat' => time(),
'exp' => time() + self::ttl(),
], $claims);
$h = self::b64u(json_encode($header, JSON_UNESCAPED_UNICODE));
$p = self::b64u(json_encode($payload, JSON_UNESCAPED_UNICODE));
$sig = hash_hmac('sha256', $h . '.' . $p, self::secret(), true);
return $h . '.' . $p . '.' . self::b64u($sig);
}
public static function decode(string $token): ?array
{
$parts = explode('.', $token);
if (count($parts) !== 3) {
return null;
}
[$h, $p, $s] = $parts;
$expected = self::b64u(hash_hmac('sha256', $h . '.' . $p, self::secret(), true));
if (!hash_equals($expected, $s)) {
return null;
}
$payload = json_decode(self::b64uDecode($p), true);
if (!is_array($payload)) {
return null;
}
if (!isset($payload['iss']) || $payload['iss'] !== self::issuer()) {
return null;
}
if (isset($payload['exp']) && $payload['exp'] < time()) {
return null;
}
return $payload;
}
private static function b64u(string $bin): string
{
return rtrim(strtr(base64_encode($bin), '+/', '-_'), '=');
}
private static function b64uDecode(string $b64): string
{
$b64 = strtr($b64, '-_', '+/');
$pad = 4 - (strlen($b64) % 4);
if ($pad < 4) {
$b64 .= str_repeat('=', $pad);
}
return base64_decode($b64);
}
}