Files
netdisk-fast-download/web-front/src/utils/playgroundApi.js
T
copilot-swe-agent[bot]andqaiu 2f55294b58 fix: 修复演练场输入密码后提示未授权访问的问题
根本原因:框架 RouterHandlerFactory 未注册 SessionHandler,
导致 ctx.session() 始终返回 null。登录时密码校验通过但认证
状态被静默丢弃,后续所有请求均返回"未授权访问"。

修复方案:将 Session 鉴权改为 Token(Bearer)鉴权:
- PlaygroundConfig: 新增 generateToken()/validateToken(),
  使用 SecureRandom 生成密码学安全 Token,并在生成时
  清理过期 Token 防止内存泄漏
- PlaygroundApi: login() 返回 Token;checkAuth() 从
  Authorization 请求头中读取并校验 Token
- playgroundApi.js: 添加请求拦截器自动携带 Token;
  login() 从响应中提取并保存 Token 到 localStorage
- Playground.vue: 后端报告未认证时同步清除 playground_token

Agent-Logs-Url: https://github.com/qaiu/netdisk-fast-download/sessions/52144d13-cd49-4a3d-b279-9b8d6cbad757

Co-authored-by: qaiu <[email protected]>
2026-04-23 01:22:09 +00:00

193 lines
5.6 KiB
JavaScript

import axios from 'axios';
// 创建axios实例,配置携带cookie
const axiosInstance = axios.create({
withCredentials: true // 重要:允许跨域请求携带cookie
});
// 请求拦截器:将存储的Token添加到Authorization请求头
axiosInstance.interceptors.request.use(config => {
const token = localStorage.getItem('playground_token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
});
/**
* 演练场API服务
*/
export const playgroundApi = {
/**
* 获取Playground状态(是否需要认证)
* @returns {Promise} 状态信息
*/
async getStatus() {
try {
const response = await axiosInstance.get('/v2/playground/status');
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || error.message || '获取状态失败');
}
},
/**
* Playground登录
* @param {string} password - 访问密码
* @returns {Promise} 登录结果
*/
async login(password) {
try {
const response = await axiosInstance.post('/v2/playground/login', { password });
const data = response.data;
// 登录成功时从响应中提取并保存Token
if ((data.code === 200 || data.success) && data.data?.token) {
localStorage.setItem('playground_token', data.data.token);
}
return data;
} catch (error) {
throw new Error(error.response?.data?.error || error.message || '登录失败');
}
},
/**
* 测试执行JavaScript代码
* @param {string} jsCode - JavaScript代码
* @param {string} shareUrl - 分享链接
* @param {string} pwd - 密码(可选)
* @param {string} method - 测试方法:parse/parseFileList/parseById
* @returns {Promise} 测试结果
*/
async testScript(jsCode, shareUrl, pwd = '', method = 'parse') {
try {
const response = await axiosInstance.post('/v2/playground/test', {
jsCode,
shareUrl,
pwd,
method
});
// 框架会自动包装成JsonResult,需要从data字段获取
if (response.data && response.data.data) {
return response.data.data;
}
// 如果没有包装,直接返回
return response.data;
} catch (error) {
const errorMsg = error.response?.data?.data?.error ||
error.response?.data?.error ||
error.response?.data?.msg ||
error.message ||
'测试执行失败';
throw new Error(errorMsg);
}
},
/**
* 获取types.js文件内容
* @returns {Promise<string>} types.js内容
*/
async getTypesJs() {
try {
const response = await axiosInstance.get('/v2/playground/types.js', {
responseType: 'text'
});
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || error.message || '获取types.js失败');
}
},
/**
* 获取解析器列表
*/
async getParserList() {
try {
const response = await axiosInstance.get('/v2/playground/parsers');
// 框架会自动包装成JsonResult,需要从data字段获取
if (response.data && response.data.data) {
return {
code: response.data.code || 200,
data: response.data.data,
msg: response.data.msg,
success: response.data.success
};
}
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || error.response?.data?.msg || error.message || '获取解析器列表失败');
}
},
/**
* 保存解析器
*/
async saveParser(jsCode) {
try {
const response = await axiosInstance.post('/v2/playground/parsers', { jsCode });
// 框架会自动包装成JsonResult
if (response.data && response.data.data) {
return {
code: response.data.code || 200,
data: response.data.data,
msg: response.data.msg,
success: response.data.success
};
}
return response.data;
} catch (error) {
const errorMsg = error.response?.data?.data?.error ||
error.response?.data?.error ||
error.response?.data?.msg ||
error.message ||
'保存解析器失败';
throw new Error(errorMsg);
}
},
/**
* 更新解析器
*/
async updateParser(id, jsCode, enabled = true) {
try {
const response = await axiosInstance.put(`/v2/playground/parsers/${id}`, { jsCode, enabled });
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || error.message || '更新解析器失败');
}
},
/**
* 删除解析器
*/
async deleteParser(id) {
try {
const response = await axiosInstance.delete(`/v2/playground/parsers/${id}`);
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || error.message || '删除解析器失败');
}
},
/**
* 根据ID获取解析器
*/
async getParserById(id) {
try {
const response = await axiosInstance.get(`/v2/playground/parsers/${id}`);
// 框架会自动包装成JsonResult
if (response.data && response.data.data) {
return {
code: response.data.code || 200,
data: response.data.data,
msg: response.data.msg,
success: response.data.success
};
}
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || error.response?.data?.msg || error.message || '获取解析器失败');
}
},
};