生产管理系统 - 每5分钟提交一次刷新token的请求
This commit is contained in:
@@ -130,6 +130,7 @@ export function LoginForm({ onRegisterClick }: LoginFormProps) {
|
|||||||
createdAt: response.data.created_at || new Date().toISOString(),
|
createdAt: response.data.created_at || new Date().toISOString(),
|
||||||
// 重要:存储token到用户对象中
|
// 重要:存储token到用户对象中
|
||||||
token: response.data.access_token || response.data.token || null,
|
token: response.data.access_token || response.data.token || null,
|
||||||
|
refreshToken:response.data.refresh_token || ''
|
||||||
};
|
};
|
||||||
|
|
||||||
// 打印登录成功日志
|
// 打印登录成功日志
|
||||||
@@ -138,7 +139,7 @@ export function LoginForm({ onRegisterClick }: LoginFormProps) {
|
|||||||
apiResponse: response.data,
|
apiResponse: response.data,
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
});
|
});
|
||||||
|
debugger
|
||||||
// 验证token是否正确存储
|
// 验证token是否正确存储
|
||||||
if (userData.token) {
|
if (userData.token) {
|
||||||
console.log('🔑 Token已存储:', userData.token.substring(0, 20) + '...');
|
console.log('🔑 Token已存储:', userData.token.substring(0, 20) + '...');
|
||||||
@@ -148,11 +149,8 @@ export function LoginForm({ onRegisterClick }: LoginFormProps) {
|
|||||||
|
|
||||||
login(userData);
|
login(userData);
|
||||||
toast.success('登录成功!正在跳转...');
|
toast.success('登录成功!正在跳转...');
|
||||||
|
|
||||||
// 跳转到个人中心页面
|
// 跳转到个人中心页面
|
||||||
setTimeout(() => {
|
|
||||||
window.location.href = '/central-config/personal-center/personal-info';
|
window.location.href = '/central-config/personal-center/personal-info';
|
||||||
}, 1000);
|
|
||||||
} else {
|
} else {
|
||||||
dispatch({ type: 'SET_ERROR', payload: '登录失败,请检查用户名和密码' });
|
dispatch({ type: 'SET_ERROR', payload: '登录失败,请检查用户名和密码' });
|
||||||
toast.error('登录失败,请检查用户名和密码');
|
toast.error('登录失败,请检查用户名和密码');
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
import React, { createContext, useContext, useState, ReactNode, useRef } from 'react';
|
||||||
import { getCurrentUserInfoApiV1AuthMeGet } from '@/lib/api/sdk.gen';
|
import { getCurrentUserInfoApiV1AuthMeGet, refreshTokenApiV1AuthRefreshPost } from '@/lib/api/sdk.gen';
|
||||||
|
|
||||||
// Cookie 操作工具
|
// Cookie 操作工具
|
||||||
const setTokenCookie = (token: string) => {
|
const setTokenCookie = (token: string) => {
|
||||||
@@ -46,6 +46,7 @@ interface AuthProviderProps {
|
|||||||
export function AuthProvider({ children }: AuthProviderProps) {
|
export function AuthProvider({ children }: AuthProviderProps) {
|
||||||
const [user, setUser] = useState<User | null>(null);
|
const [user, setUser] = useState<User | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const refreshTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
const login = (userData: User) => {
|
const login = (userData: User) => {
|
||||||
setUser(userData);
|
setUser(userData);
|
||||||
@@ -58,6 +59,9 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
|
// 登录成功后,启动 token 自动刷新定时器
|
||||||
|
startTokenRefresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
@@ -66,12 +70,127 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
removeTokenCookie(); // 清除 cookie
|
removeTokenCookie(); // 清除 cookie
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
|
// 清除定时器
|
||||||
|
if (refreshTimerRef.current) {
|
||||||
|
clearInterval(refreshTimerRef.current);
|
||||||
|
refreshTimerRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 跳转到登录页
|
// 跳转到登录页
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 刷新 token 的函数
|
||||||
|
const refreshAccessToken = async () => {
|
||||||
|
try {
|
||||||
|
const storedUser = localStorage.getItem('user');
|
||||||
|
if (!storedUser) {
|
||||||
|
console.warn('⚠️ 未找到用户信息,无法刷新 token');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userData = JSON.parse(storedUser);
|
||||||
|
if (!userData.token) {
|
||||||
|
console.warn('⚠️ 用户信息中没有 token,无法刷新');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🔄 开始刷新 token...');
|
||||||
|
console.log('📝 当前 token (前20字符):', userData.token.substring(0, 20) + '...');
|
||||||
|
|
||||||
|
const response = await refreshTokenApiV1AuthRefreshPost({
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${userData.refreshToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('📨 刷新接口响应:', response);
|
||||||
|
|
||||||
|
// 检查响应数据结构
|
||||||
|
if (response.data) {
|
||||||
|
console.log('📋 响应数据结构:', JSON.stringify(response.data, null, 2));
|
||||||
|
|
||||||
|
// 尝试多种可能的 token 字段名
|
||||||
|
const newToken = response.data.access_token || ""
|
||||||
|
const refreshToken = response.data.refresh_token || ""
|
||||||
|
|
||||||
|
if (newToken) {
|
||||||
|
// 更新用户信息中的 token
|
||||||
|
const updatedUserData = {
|
||||||
|
...userData,
|
||||||
|
token: newToken,
|
||||||
|
refreshToken:refreshToken,
|
||||||
|
// 如果有其他 token 相关字段也一并更新
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新 localStorage
|
||||||
|
localStorage.setItem('user', JSON.stringify(updatedUserData));
|
||||||
|
|
||||||
|
// 更新状态
|
||||||
|
setUser(updatedUserData);
|
||||||
|
|
||||||
|
// 更新 cookie
|
||||||
|
setTokenCookie(newToken);
|
||||||
|
|
||||||
|
console.log('✅ Token 刷新成功');
|
||||||
|
console.log('🔑 新 token (前20字符):', newToken.substring(0, 20) + '...');
|
||||||
|
} else {
|
||||||
|
console.error('❌ Token 刷新失败:响应中未找到 token 字段');
|
||||||
|
console.log('🔍 可用字段:', Object.keys(response.data));
|
||||||
|
// 先不登出,记录错误,让用户继续使用当前 token
|
||||||
|
console.log('⚠️ 暂不执行登出,继续使用当前 token');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('❌ Token 刷新失败:响应数据为空');
|
||||||
|
console.log('📊 完整响应:', response);
|
||||||
|
// 先不登出,可能是接口问题
|
||||||
|
console.log('⚠️ 暂不执行登出,可能是接口问题');
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('❌ Token 刷新失败:', error);
|
||||||
|
console.log('📝 错误详情:', {
|
||||||
|
message: error.message,
|
||||||
|
status: error.response?.status,
|
||||||
|
statusText: error.response?.statusText,
|
||||||
|
data: error.response?.data
|
||||||
|
});
|
||||||
|
|
||||||
|
// 根据错误类型决定是否登出
|
||||||
|
if (error.response?.status === 401) {
|
||||||
|
console.log('🔒 Token 已过期,执行登出');
|
||||||
|
logout();
|
||||||
|
} else {
|
||||||
|
console.log('⚠️ 网络或服务器错误,暂不执行登出');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 启动定时刷新 token
|
||||||
|
const startTokenRefresh = () => {
|
||||||
|
// 清除之前的定时器
|
||||||
|
if (refreshTimerRef.current) {
|
||||||
|
clearInterval(refreshTimerRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每 1 分钟刷新一次 token
|
||||||
|
refreshTimerRef.current = setInterval(() => {
|
||||||
|
refreshAccessToken();
|
||||||
|
}, 5 * 60 * 1000); // 60 秒 = 1 分钟
|
||||||
|
|
||||||
|
console.log('🕐 Token 自动刷新定时器已启动(每5分钟)');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 停止定时刷新 token
|
||||||
|
const stopTokenRefresh = () => {
|
||||||
|
if (refreshTimerRef.current) {
|
||||||
|
clearInterval(refreshTimerRef.current);
|
||||||
|
refreshTimerRef.current = null;
|
||||||
|
console.log('⏹️ Token 自动刷新定时器已停止');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 验证当前用户信息
|
// 验证当前用户信息
|
||||||
const validateUser = async () => {
|
const validateUser = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -92,11 +211,15 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
|
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
// 更新用户信息(可能包含最新的权限、角色等)
|
// 更新用户信息(可能包含最新的权限、角色等)
|
||||||
setUser({
|
const updatedUserData = {
|
||||||
...userData,
|
...userData,
|
||||||
...response.data, // 合并最新的用户信息
|
...response.data, // 合并最新的用户信息
|
||||||
});
|
};
|
||||||
|
setUser(updatedUserData);
|
||||||
console.log('✅ 用户验证成功,最新用户信息:', response.data);
|
console.log('✅ 用户验证成功,最新用户信息:', response.data);
|
||||||
|
|
||||||
|
// 验证成功后,启动 token 自动刷新定时器
|
||||||
|
startTokenRefresh();
|
||||||
} else {
|
} else {
|
||||||
// Token无效,清除用户信息
|
// Token无效,清除用户信息
|
||||||
console.warn('⚠️ Token验证失败,清除用户信息');
|
console.warn('⚠️ Token验证失败,清除用户信息');
|
||||||
@@ -133,6 +256,14 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|||||||
validateUser();
|
validateUser();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// 清理定时器
|
||||||
|
React.useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
// 组件卸载时清理定时器
|
||||||
|
stopTokenRefresh();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const value: AuthContextType = {
|
const value: AuthContextType = {
|
||||||
user,
|
user,
|
||||||
login,
|
login,
|
||||||
|
|||||||
Reference in New Issue
Block a user