secretKey = strlen($secret) >= 32 ? $secret : hash('sha256', $secret !== '' ? $secret : 'nl_wx_jwt_fallback'); } public static function getInstance(): null|static { $name = get_called_class(); if (!isset(self::$_instance[$name])) { self::$_instance[$name] = new static(); } return self::$_instance[$name]; } /** * 签发令牌 */ public function issue(int $userId, string $appCode = ''): string { $now = time(); return JWT::encode([ 'iat' => $now, 'exp' => $now + (int) config('nl.wx.token_ttl', 30 * 24 * 3600), 'scope' => self::SCOPE, 'uid' => $userId, 'app' => $appCode, ], $this->secretKey, 'HS256'); } /** * 校验令牌并返回用户;失败返回 null 由中间件统一响应 */ public function resolveUser(?string $token): ?array { if (empty($token)) { return null; } try { $payload = JWT::decode($token, new Key($this->secretKey, 'HS256')); } catch (\Throwable) { return null; } if (($payload->scope ?? '') !== self::SCOPE) { return null; } $userId = (int) ($payload->uid ?? 0); if ($userId <= 0) { return null; } // 每次请求回查用户:倍率、价格可见性、是否被停用都可能刚被后台改过 $user = WxUserModel::where('id', $userId)->where('deleted_at', 0)->first(); if (empty($user)) { return null; } $user = $user->toArray(); unset($user['session_key']); return $user; } /** * 取当前请求的小程序用户,取不到直接中断 */ public function requireUser(): array { $user = request()->attributes->get('wx_user'); if (!empty($user)) { return $user; } $user = $this->resolveUser(request()->bearerToken()); if (empty($user)) { UtilsService::getInstance()->notAuth('请先登录'); } return $user; } }