fix: bbs与ai存储refreshToken

This commit is contained in:
Gsh
2025-06-29 00:57:57 +08:00
parent 03de576d8c
commit 39eb4bef07
7 changed files with 151 additions and 81 deletions

View File

@@ -3,6 +3,9 @@ import { post } from '@/utils/request';
export const login = (data: LoginDTO) => post<LoginVO>('/auth/login', data).json();
// 刷新token
export const updateToken = (data: any) => post<any>('/account/refresh', data).json();
// 邮箱验证码
export const emailCode = (data: EmailCodeDTO) => post('/resource/email/code', data).json();

View File

@@ -76,8 +76,8 @@ function handleThirdPartyLogin() {
try {
// 清理监听
window.removeEventListener('message', messageHandler);
const { token } = event.data;
userStore.setToken(token);
const { token, refreshToken } = event.data;
userStore.setToken(token, refreshToken);
const resUserInfo = await getUserInfo();
userStore.setUserInfo(resUserInfo.data);
// 关闭弹窗

View File

@@ -6,12 +6,20 @@ export const useUserStore = defineStore(
'user',
() => {
const token = ref<string>();
const refreshToken = ref<string | undefined>();
const router = useRouter();
const setToken = (value: string) => {
const setToken = (value: string, refreshValue?: string) => {
// 让接口报401
// token.value = `${value}cdsfds`;
token.value = value;
if (refreshValue) {
refreshToken.value = refreshValue;
}
};
const clearToken = () => {
token.value = void 0;
refreshToken.value = void 0;
};
const userInfo = ref<LoginUser>();
@@ -44,6 +52,7 @@ export const useUserStore = defineStore(
return {
token,
refreshToken,
setToken,
clearToken,
userInfo,

View File

@@ -1,26 +1,21 @@
import type { HookFetchPlugin } from 'hook-fetch';
import FingerprintJS from '@fingerprintjs/fingerprintjs'; // 新增指纹库
import FingerprintJS from '@fingerprintjs/fingerprintjs';
import { ElMessage } from 'element-plus';
import hookFetch from 'hook-fetch';
import { sseTextDecoderPlugin } from 'hook-fetch/plugins';
import router from '@/routers';
import { useUserStore } from '@/stores';
// 初始化指纹(单例模式)
// 初始化指纹
const fpPromise = FingerprintJS.load();
// 获取浏览器指纹(缓存结果)
async function getFingerprint(): Promise<string> {
const fp = await fpPromise;
const { visitorId } = await fp.get();
return visitorId;
return (await fp.get()).visitorId;
}
// 标准响应格式
interface BaseResponse<T = any> {
code: number;
code?: number; // 变为可选字段
data: T;
msg: string;
msg?: string;
}
declare module 'hook-fetch' {
@@ -29,6 +24,10 @@ declare module 'hook-fetch' {
}
}
// 刷新控制变量
let isRefreshing = false;
let pendingRequests: (() => void)[] = [];
export const request = hookFetch.create<BaseResponse>({
baseURL: import.meta.env.VITE_WEB_BASE_API,
headers: {
@@ -37,7 +36,7 @@ export const request = hookFetch.create<BaseResponse>({
plugins: [
sseTextDecoderPlugin({ json: true, prefix: 'data:' }),
{
name: 'fingerprint-plugin', // 新增指纹插件
name: 'fingerprint-plugin',
beforeRequest: async (config) => {
try {
const fingerprint = await getFingerprint();
@@ -45,66 +44,110 @@ export const request = hookFetch.create<BaseResponse>({
config.headers.set('X-Fingerprint', fingerprint);
}
catch (error) {
console.error('Failed to generate fingerprint:', error);
console.error('指纹生成失败:', error);
}
return config;
},
},
{
name: 'adapt-array-response',
afterResponse: async (response) => {
if (typeof response.result?.code === 'number') {
return response;
name: 'jwt-auth',
beforeRequest: (config) => {
const userStore = useUserStore();
if (userStore.token) {
config.headers = new Headers(config.headers);
config.headers.set('Authorization', `Bearer ${userStore.token}`);
}
return {
...response,
result: {
code: 200,
data: response.result,
msg: 'success',
},
};
return config;
},
afterResponse: async (response: any, config: any) => {
const userStore = useUserStore();
console.log('网络请求响应----', response);
// 成功请求HTTP状态码200-299
if (response.ok) {
// 兼容响应体可能没有code字段的情况
const data = await response.json();
return {
...response,
result: data.code ? data : { code: 200, data, msg: 'success' },
};
}
// 处理HTTP状态码401
if (response.status === 401) {
// 刷新Token接口自身失败
if (config.url?.includes('/account/refresh')) {
userStore.logout();
userStore.openLoginDialog();
throw new Error('刷新Token失败');
}
// 将请求加入队列
if (isRefreshing) {
return new Promise((resolve) => {
pendingRequests.push(() => resolve(request(config)));
});
}
// 开始刷新流程
isRefreshing = true;
try {
const refreshRes = await request.post('/account/refresh', {
refresh_token: userStore.refreshToken,
}).json();
// 更新Token
userStore.setToken(refreshRes.data.token, refreshRes.data.refreshToken);
// 重试原始请求
config.headers.set('Authorization', `Bearer ${refreshRes.data.token}`);
const retryResponse = await request(config);
// 执行等待中的请求
pendingRequests.forEach(cb => cb());
pendingRequests = [];
return retryResponse;
}
catch (error) {
// 刷新失败清除状态
userStore.logout();
userStore.openLoginDialog();
throw error;
}
finally {
isRefreshing = false;
}
}
// 处理HTTP状态码403
if (response.status === 403) {
router.replace({ name: '403' });
const errorMsg = (await response.json().catch(() => ({})))?.msg || '无权限访问';
ElMessage.error(errorMsg);
throw new Error('Forbidden');
}
// 其他错误状态码
const errorData = await response.json().catch(() => ({}));
ElMessage.error(errorData.msg || `请求失败: ${response.status}`);
throw errorData;
},
// 错误处理
async onError(error: any, config: any) {
console.log('网络请求错误----', error);
console.log('网络请求错误--config--', config);
// 可以处理或转换错误
if (error.status === 401) {
// 处理未授权错误
return new Error('Please login first');
}
return error;
},
},
],
});
// JWT插件保持原有逻辑)
function jwtPlugin(): HookFetchPlugin<BaseResponse> {
const userStore = useUserStore();
return {
name: 'jwt',
beforeRequest: async (config) => {
if (userStore.token) {
config.headers = new Headers(config.headers);
config.headers.set('authorization', `Bearer ${userStore.token}`);
}
return config;
},
afterResponse: async (response) => {
if (response.result?.code === 200)
return response;
if (response.result?.code === 403) {
router.replace({ name: '403' });
ElMessage.error(response.result?.msg);
return Promise.reject(response);
}
if (response.result?.code === 401) {
userStore.logout();
userStore.openLoginDialog();
}
ElMessage.error(response.result?.msg);
return Promise.reject(response);
},
};
}
request.use(jwtPlugin());
// 导出方法(保持原有)
// 保持原有导出
export const post = request.post;
export const get = request.get;
export const put = request.put;