更新若干功能

This commit is contained in:
2026-08-19 08:16:49 +08:00
parent 4979bb83d2
commit 72bc6502eb
56 changed files with 3627 additions and 343 deletions

View File

@@ -69,7 +69,11 @@ class JWTService
$payload = [
'iat' => $issuedAt,
'exp' => $expirationTime,
'data' => $data
// sub 是标准声明,网关/旧客户端剥掉自定义 data 时还能靠它找回用户
'sub' => (string) ($data['id'] ?? ''),
// 与小程序 tokenscope=wx区分两边共用 JWT_SECRET 但不能互认
'scope' => 'admin',
'data' => $data,
];
RedisService::getInstance()->init(config('nl.redis.jwt'))->set($data['id'], json_encode($data));
return JWT::encode($payload, $this->secretKey, 'HS256');
@@ -83,9 +87,14 @@ class JWTService
public function parseToken(): ?object
{
try {
if (empty($this->token)) return UtilsService::getInstance()->notAuth('请先登录');
if (empty($this->token)) {
return UtilsService::getInstance()->notAuth('请先登录');
}
return JWT::decode($this->token, new Key($this->secretKey, 'HS256'));
} catch (Exception $e) {
if ((int) $e->getCode() === 401) {
throw $e;
}
return UtilsService::getInstance()->notAuth('【1】Token解析失败请重新登录'. $e->getMessage());
}
}
@@ -100,14 +109,59 @@ class JWTService
{
try {
$jwt = $this->parseToken();
$user = RedisService::getInstance()->init(config('nl.redis.jwt'))->get($jwt->data->id);
if (empty($user)) return UtilsService::getInstance()->notAuth('登录状态过期');
return json_decode($user, true);
} catch (Exception $e) {
$payload = json_decode(json_encode($jwt), true);
if (is_array($payload) && ($payload['scope'] ?? '') === 'wx') {
return UtilsService::getInstance()->notAuth('请使用后台账号登录');
}
$data = $this->extractUserData($jwt);
$userId = (int) ($data['id'] ?? 0);
if ($userId <= 0) {
return UtilsService::getInstance()->notAuth('Token 无效,请重新登录');
}
$user = RedisService::getInstance()->init(config('nl.redis.jwt'))->get($userId);
if (empty($user)) {
// Redis 会话丢了但签名有效:用 payload 顶住,避免刚登录就被踢
return $data;
}
$decoded = json_decode($user, true);
return is_array($decoded) ? $decoded : $data;
} catch (\Throwable $e) {
if ((int) $e->getCode() === 401) {
throw $e;
}
return UtilsService::getInstance()->notAuth('【2】Token解析失败请重新登录'. $e->getMessage());
}
}
/**
* 从解码后的 JWT 取出用户数据
*
* 本系统签发的是 { data: { id, ... } };有的网关/ token 会把字段摊到顶层,
* 或只留 sub。这里都认避免再出现 Undefined property::$data。
*/
public function extractUserData(?object $jwt): array
{
if (!is_object($jwt)) {
return [];
}
$payload = json_decode(json_encode($jwt), true);
if (!is_array($payload)) {
return [];
}
$data = $payload['data'] ?? null;
if (is_array($data) && $data !== []) {
return $data;
}
if (is_object($data)) {
return (array) $data;
}
$id = $payload['id'] ?? $payload['sub'] ?? 0;
if ((int) $id > 0) {
return array_merge($payload, ['id' => (int) $id]);
}
return [];
}
/**
* 续签 JWT Token
* @return string|null 新的 JWT 字符串或者 null 如果原 token 已过期或无效
@@ -116,11 +170,12 @@ class JWTService
public function refreshToken(): ?string
{
$decoded = $this->parseToken();
if ($decoded === null || !property_exists($decoded, 'data')) {
$data = $this->extractUserData($decoded);
if (($data['id'] ?? 0) <= 0) {
return null;
}
return $this->generateToken((array)$decoded->data);
return $this->generateToken($data);
}
/**