addSeconds(config('app.jwt.expire'))->timestamp; // 标准JWT载荷 + 自定义载荷 $jwtPayload = array_merge([ 'iss' => config('app.url'), // 签发者 'iat' => Carbon::now()->timestamp, // 签发时间 'exp' => $expiresAt, // 过期时间 'nbf' => Carbon::now()->timestamp, // 生效时间 ], $payload); return JWT::encode($jwtPayload, $secret, $algorithm); } /** * 生成刷新令牌 * @param int $userId 用户ID * @return string */ public function generateRefreshToken(int $userId): string { $secret = config('app.jwt.secret'); $algorithm = config('app.jwt.algorithm'); $expiresAt = Carbon::now()->addSeconds(config('app.jwt.refresh_expire'))->timestamp; $refreshPayload = [ 'iss' => config('app.url'), 'iat' => Carbon::now()->timestamp, 'exp' => $expiresAt, 'sub' => 'refresh_token', // 标识为刷新令牌 'user_id' => $userId, ]; return JWT::encode($refreshPayload, $secret, $algorithm); } /** * 验证并解析JWT令牌 * @param string $token * @return array 解析后的载荷 * @throws ExpiredException|SignatureInvalidException|InvalidArgumentException */ public function verifyToken(string $token): array { $secret = config('app.jwt.secret'); $algorithm = config('app.jwt.algorithm'); try { // 验证并解析令牌 $decoded = JWT::decode($token, new Key($secret, $algorithm)); return (array) $decoded; } catch (ExpiredException $e) { throw new ExpiredException('Token已过期', 401); } catch (SignatureInvalidException $e) { throw new SignatureInvalidException('Token签名无效', 400); } catch (InvalidArgumentException $e) { throw new InvalidArgumentException('Token格式错误', 400); } } /** * 解析令牌(不验证签名/过期,仅用于读取载荷) * @param string $token * @return array */ public function decodeTokenWithoutVerify(string $token): array { $parts = explode('.', $token); if (count($parts) !== 3) { throw new InvalidArgumentException('Token格式错误'); } $payload = json_decode(base64_decode($parts[1]), true); return $payload ?: []; } }