主要改动: - 在插件激活时检查Token是否过期,过期则自动清除session - 修复Token检查逻辑,从session.accessToken获取Token而非globalState - 在消息发送前检查Token有效性,过期则提示重新登录 - 优化ICHelperPanel和ICViewProvider的Token过期处理 - 修复退出登录命令名错误(iccoder.logout -> ic-coder.logout) - 添加Token过期检查文档文档
7.3 KiB
7.3 KiB
Token 过期检查实现方案
1. 概述
实现三个关键时机的 Token 过期检查:
- 插件激活时
- 发起 API 请求前
- 用户交互时(打开面板/侧边栏)
2. 数据存储
2.1 存储位置
使用 VS Code 的 globalState 存储:
context.globalState.update('tokenExp', exp);
2.2 存储内容
token: 用户 tokentokenExp: 过期时间戳(秒)userInfo: 用户信息
3. 核心函数设计
3.1 过期检查函数
/**
* 检查 token 是否过期
* @param exp - 过期时间戳(秒)
* @param bufferSeconds - 提前判断过期的缓冲时间(默认 60 秒)
* @returns true 表示已过期或即将过期
*/
function isTokenExpired(exp: number | undefined, bufferSeconds: number = 60): boolean {
if (!exp) {
return true; // 没有过期时间,视为已过期
}
const now = Math.floor(Date.now() / 1000); // 当前时间戳(秒)
return now >= (exp - bufferSeconds); // 提前 60 秒判断过期
}
3.2 清除登录状态函数
/**
* 清除所有登录相关状态
*/
async function clearAuthState(context: vscode.ExtensionContext): Promise<void> {
await context.globalState.update('token', undefined);
await context.globalState.update('tokenExp', undefined);
await context.globalState.update('userInfo', undefined);
}
3.3 统一过期处理函数
/**
* 处理 token 过期情况
* @param context - 扩展上下文
* @param showMessage - 是否显示提示消息
*/
async function handleTokenExpired(
context: vscode.ExtensionContext,
showMessage: boolean = true
): Promise<void> {
await clearAuthState(context);
if (showMessage) {
const action = await vscode.window.showWarningMessage(
'登录已过期,请重新登录',
'立即登录'
);
if (action === '立即登录') {
// 触发登录流程(打开登录面板)
vscode.commands.executeCommand('ic-coder.openPanel');
}
}
}
4. 三个检查时机实现
4.1 插件激活时检查
位置: src/extension.ts 的 activate 函数
实现:
export async function activate(context: vscode.ExtensionContext) {
console.log('IC Coder 插件正在激活...');
// 1. 检查 token 是否过期
const tokenExp = context.globalState.get<number>('tokenExp');
if (isTokenExpired(tokenExp)) {
// 静默清除,不显示提示(避免启动时打扰用户)
await handleTokenExpired(context, false);
}
// ... 其他激活逻辑
}
说明: 启动时静默检查,如果过期则清除状态,但不弹窗提示
4.2 发起 API 请求前检查
位置: src/utils/messageHandler.ts 的 API 请求函数
实现:
// 在发送消息到后端前检查
async function sendMessageToBackend(message: string, context: vscode.ExtensionContext) {
// 1. 检查 token 是否过期
const tokenExp = context.globalState.get<number>('tokenExp');
if (isTokenExpired(tokenExp)) {
await handleTokenExpired(context, true); // 显示提示
return; // 中断请求
}
const token = context.globalState.get<string>('token');
if (!token) {
vscode.window.showWarningMessage('请先登录');
return;
}
// 2. 继续发送请求
// ... 原有请求逻辑
}
说明: 每次 API 请求前检查,如果过期则提示用户并中断请求
4.3 用户交互时检查
位置:
src/panels/ICHelperPanel.ts- 打开聊天面板时src/views/ICViewProvider.ts- 侧边栏视图加载时
实现 - 聊天面板:
// ICHelperPanel.ts
public static render(extensionUri: vscode.Uri, context: vscode.ExtensionContext) {
// 1. 检查 token 是否过期
const tokenExp = context.globalState.get<number>('tokenExp');
if (isTokenExpired(tokenExp)) {
handleTokenExpired(context, true); // 显示提示
// 继续渲染面板,但会显示未登录状态
}
// 2. 创建或显示面板
// ... 原有逻辑
}
实现 - 侧边栏视图:
// ICViewProvider.ts
public resolveWebviewView(webviewView: vscode.WebviewView) {
// 1. 检查 token 是否过期
const tokenExp = this._context.globalState.get<number>('tokenExp');
if (isTokenExpired(tokenExp)) {
handleTokenExpired(this._context, false); // 静默清除
// 继续渲染,显示未登录状态
}
// 2. 渲染视图
// ... 原有逻辑
}
说明: 打开面板时检查,聊天面板显示提示,侧边栏静默处理
5. 后端响应处理
5.1 保存 exp 字段
位置: src/utils/messageHandler.ts 处理登录响应的地方
实现:
// 处理登录成功响应
if (response.data.token) {
await context.globalState.update('token', response.data.token);
// 保存过期时间
if (response.data.exp) {
await context.globalState.update('tokenExp', response.data.exp);
}
// 保存用户信息
if (response.data.userInfo) {
await context.globalState.update('userInfo', response.data.userInfo);
}
}
5.2 处理 401 响应
实现:
// API 请求错误处理
if (error.response?.status === 401) {
// 后端返回 401,说明 token 无效或过期
await handleTokenExpired(context, true);
return;
}
6. 工具函数位置
建议创建新文件 src/utils/authHelper.ts:
import * as vscode from 'vscode';
export function isTokenExpired(exp: number | undefined, bufferSeconds: number = 60): boolean {
if (!exp) {
return true;
}
const now = Math.floor(Date.now() / 1000);
return now >= (exp - bufferSeconds);
}
export async function clearAuthState(context: vscode.ExtensionContext): Promise<void> {
await context.globalState.update('token', undefined);
await context.globalState.update('tokenExp', undefined);
await context.globalState.update('userInfo', undefined);
}
export async function handleTokenExpired(
context: vscode.ExtensionContext,
showMessage: boolean = true
): Promise<void> {
await clearAuthState(context);
if (showMessage) {
const action = await vscode.window.showWarningMessage(
'登录已过期,请重新登录',
'立即登录'
);
if (action === '立即登录') {
vscode.commands.executeCommand('ic-coder.openPanel');
}
}
}
7. 测试场景
- 启动测试: 设置过期的 exp,重启插件,验证状态被清除
- 请求测试: 设置即将过期的 exp,发送消息,验证被拦截
- 交互测试: 设置过期的 exp,打开面板,验证提示显示
- 401 测试: 模拟后端返回 401,验证状态清除
8. 注意事项
- 使用 60 秒缓冲时间,避免请求中途过期
- 启动和侧边栏加载时静默处理,避免打扰用户
- 主动操作(发消息、打开聊天面板)时显示提示
- 所有时间戳使用秒为单位(与后端保持一致)
- 过期检查应该在所有需要 token 的操作前执行
9. 修改文件清单
需要修改的文件:
- 新建:
src/utils/authHelper.ts- 认证辅助工具函数 - 修改:
src/extension.ts- 插件激活时检查 - 修改:
src/utils/messageHandler.ts- API 请求前检查 + 保存 exp + 处理 401 - 修改:
src/panels/ICHelperPanel.ts- 打开聊天面板时检查 - 修改:
src/views/ICViewProvider.ts- 侧边栏加载时检查