feat:实现Token过期检查和自动清除机制

主要改动:
   - 在插件激活时检查Token是否过期,过期则自动清除session
   - 修复Token检查逻辑,从session.accessToken获取Token而非globalState
   - 在消息发送前检查Token有效性,过期则提示重新登录
   - 优化ICHelperPanel和ICViewProvider的Token过期处理
   - 修复退出登录命令名错误(iccoder.logout -> ic-coder.logout)
   - 添加Token过期检查文档文档
This commit is contained in:
Roe-xin
2026-01-26 18:41:52 +08:00
parent 423c9ddb0e
commit 9296b10150
7 changed files with 472 additions and 19 deletions

View File

@ -6,11 +6,11 @@
* JWT Payload 接口
*/
export interface JwtPayload {
sub?: string; // subject (通常是 userId)
userId?: number; // 用户ID (驼峰命名)
user_id?: number; // 用户ID (下划线命名)
exp?: number; // 过期时间
iat?: number; // 签发时间
sub?: string; // subject (通常是 userId)
userId?: number; // 用户ID (驼峰命名)
user_id?: number; // 用户ID (下划线命名)
exp?: number; // 过期时间
iat?: number; // 签发时间
[key: string]: unknown;
}
@ -21,9 +21,9 @@ export interface JwtPayload {
*/
export function parseJwtPayload(token: string): JwtPayload | null {
try {
const parts = token.split('.');
const parts = token.split(".");
if (parts.length !== 3) {
console.warn('[JWT] token 格式不正确期望3部分实际:', parts.length);
console.warn("[JWT] token 格式不正确期望3部分实际:", parts.length);
return null;
}
@ -31,17 +31,17 @@ export function parseJwtPayload(token: string): JwtPayload | null {
const payload = parts[1];
// base64url 转 base64
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
// 解码
const jsonStr = Buffer.from(base64, 'base64').toString('utf-8');
const jsonStr = Buffer.from(base64, "base64").toString("utf-8");
const parsed = JSON.parse(jsonStr);
console.log('[JWT] 解析成功, payload 字段:', Object.keys(parsed));
console.log('[JWT] payload 内容:', JSON.stringify(parsed));
console.log("[JWT] 解析成功, payload 字段:", Object.keys(parsed));
console.log("[JWT] payload 内容:", JSON.stringify(parsed));
return parsed;
} catch (error) {
console.error('[JWT] 解析失败:', error);
console.error("[JWT] 解析失败:", error);
return null;
}
}
@ -68,7 +68,7 @@ export function getUserIdFromToken(token: string): string | null {
return String(payload.sub);
}
console.warn('[JWT] payload 中没有 user_id, userId 或 sub 字段');
console.warn("[JWT] payload 中没有 user_id, userId 或 sub 字段");
return null;
}
@ -78,14 +78,17 @@ export function getUserIdFromToken(token: string): string | null {
* @param bufferSeconds 提前多少秒判定为过期默认60秒
* @returns true 表示已过期false 表示未过期null 表示无法判断
*/
export function isTokenExpired(token: string, bufferSeconds: number = 60): boolean | null {
export function isTokenExpired(
token: string,
bufferSeconds: number = 60,
): boolean | null {
const payload = parseJwtPayload(token);
if (!payload) {
return null;
}
if (payload.exp === undefined) {
console.warn('[JWT] payload 中没有 exp 字段,无法判断过期');
console.warn("[JWT] payload 中没有 exp 字段,无法判断过期");
return null;
}
@ -94,7 +97,7 @@ export function isTokenExpired(token: string, bufferSeconds: number = 60): boole
const isExpired = now >= expTime;
if (isExpired) {
console.warn('[JWT] token 已过期exp:', payload.exp, '当前:', now);
console.warn("[JWT] token 已过期exp:", payload.exp, "当前:", now);
}
return isExpired;