/** * Token管理服务 * 负责处理OAuth访问令牌的刷新和管理 * 如果需要添加新的Token相关功能: * 1. 优先考虑在 `TokenManager` 中添加 * 2. 如果需要新的网络请求,在 `OAuthClient` 中添加 */ import { OAuthClient } from "./oauth-client"; import { OAUTH_CONFIG } from "~/config/api-config"; interface TokenInfo { accessToken: string; refreshToken: string; tokenIssuedAt: number; tokenExpiresIn: number; } interface RefreshResult { success: boolean; newTokenInfo?: TokenInfo; error?: string; } /** * Token管理服务 * 负责处理OAuth访问令牌的刷新和管理 */ export class TokenManager { private oauthClient: OAuthClient; constructor() { this.oauthClient = new OAuthClient(OAUTH_CONFIG); } /** * 检查token是否过期 */ isTokenExpired(tokenInfo: TokenInfo): boolean { const now = Date.now(); const expiresAt = tokenInfo.tokenIssuedAt + (tokenInfo.tokenExpiresIn * 1000); return now >= expiresAt; } /** * 检查token是否需要刷新(提前5分钟) */ shouldRefreshToken(tokenInfo: TokenInfo, refreshThresholdMinutes: number = 5): boolean { const now = Date.now(); const expiresAt = tokenInfo.tokenIssuedAt + (tokenInfo.tokenExpiresIn * 1000); const refreshThreshold = refreshThresholdMinutes * 60 * 1000; return now >= (expiresAt - refreshThreshold); } /** * 获取token剩余有效时间(秒) */ getTokenRemainingTime(tokenInfo: TokenInfo): number { const now = Date.now(); const expiresAt = tokenInfo.tokenIssuedAt + (tokenInfo.tokenExpiresIn * 1000); return Math.floor((expiresAt - now) / 1000); } /** * 刷新访问令牌 */ async refreshToken(refreshToken: string): Promise { try { console.log("开始刷新访问令牌..."); const newTokenResponse = await this.oauthClient.refreshAccessToken(refreshToken); if (!newTokenResponse) { console.error("刷新令牌失败:服务器返回空响应"); return { success: false, error: "服务器返回空响应" }; } const newTokenInfo: TokenInfo = { accessToken: newTokenResponse.access_token, refreshToken: newTokenResponse.refresh_token, tokenIssuedAt: Date.now(), tokenExpiresIn: newTokenResponse.expires_in }; console.log(`令牌刷新成功,新令牌有效期: ${newTokenResponse.expires_in}秒`); return { success: true, newTokenInfo }; } catch (error) { console.error("刷新令牌时发生错误:", error); return { success: false, error: error instanceof Error ? error.message : "未知错误" }; } } /** * 检查并自动刷新token(如果需要) */ async checkAndRefreshToken(tokenInfo: TokenInfo): Promise { // 如果token已过期,必须刷新 if (this.isTokenExpired(tokenInfo)) { console.log("Token已过期,尝试刷新..."); return this.refreshToken(tokenInfo.refreshToken); } // 如果token即将过期,主动刷新 if (this.shouldRefreshToken(tokenInfo)) { const remainingTime = this.getTokenRemainingTime(tokenInfo); console.log(`Token将在${remainingTime}秒后过期,主动刷新...`); return this.refreshToken(tokenInfo.refreshToken); } // Token仍然有效,无需刷新 return { success: true, newTokenInfo: tokenInfo }; } /** * 格式化token到期时间 */ formatTokenExpiry(tokenInfo: TokenInfo): string { const expiresAt = new Date(tokenInfo.tokenIssuedAt + (tokenInfo.tokenExpiresIn * 1000)); return expiresAt.toLocaleString('zh-CN'); } /** * 获取token状态信息(用于调试) */ getTokenStatus(tokenInfo: TokenInfo): { isExpired: boolean; shouldRefresh: boolean; remainingTime: number; expiryTime: string; } { return { isExpired: this.isTokenExpired(tokenInfo), shouldRefresh: this.shouldRefreshToken(tokenInfo), remainingTime: this.getTokenRemainingTime(tokenInfo), expiryTime: this.formatTokenExpiry(tokenInfo) }; } } // 导出单例实例 export const tokenManager = new TokenManager();