From cb46f91846a4931c77d70c54097c8abf9fbb3b12 Mon Sep 17 00:00:00 2001 From: peng Date: Sat, 1 Nov 2025 10:24:00 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=9F=E4=BA=A7=E7=AE=A1=E7=90=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=20-=20=E6=AF=8F5=E5=88=86=E9=92=9F=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=E5=88=B7=E6=96=B0token=E7=9A=84=E8=AF=B7?= =?UTF-8?q?=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/(auth)/login/components/LoginForm.tsx | 6 +- crop-x/src/components/auth/AuthContext.tsx | 139 +++++++++++++++++- 2 files changed, 137 insertions(+), 8 deletions(-) diff --git a/crop-x/src/app/(auth)/login/components/LoginForm.tsx b/crop-x/src/app/(auth)/login/components/LoginForm.tsx index e19eb7c..6af23e1 100644 --- a/crop-x/src/app/(auth)/login/components/LoginForm.tsx +++ b/crop-x/src/app/(auth)/login/components/LoginForm.tsx @@ -130,6 +130,7 @@ export function LoginForm({ onRegisterClick }: LoginFormProps) { createdAt: response.data.created_at || new Date().toISOString(), // 重要:存储token到用户对象中 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, timestamp: new Date().toISOString() }); - + debugger // 验证token是否正确存储 if (userData.token) { console.log('🔑 Token已存储:', userData.token.substring(0, 20) + '...'); @@ -148,11 +149,8 @@ export function LoginForm({ onRegisterClick }: LoginFormProps) { login(userData); toast.success('登录成功!正在跳转...'); - // 跳转到个人中心页面 - setTimeout(() => { window.location.href = '/central-config/personal-center/personal-info'; - }, 1000); } else { dispatch({ type: 'SET_ERROR', payload: '登录失败,请检查用户名和密码' }); toast.error('登录失败,请检查用户名和密码'); diff --git a/crop-x/src/components/auth/AuthContext.tsx b/crop-x/src/components/auth/AuthContext.tsx index dc2565c..1b9e092 100644 --- a/crop-x/src/components/auth/AuthContext.tsx +++ b/crop-x/src/components/auth/AuthContext.tsx @@ -1,7 +1,7 @@ 'use client'; -import React, { createContext, useContext, useState, ReactNode } from 'react'; -import { getCurrentUserInfoApiV1AuthMeGet } from '@/lib/api/sdk.gen'; +import React, { createContext, useContext, useState, ReactNode, useRef } from 'react'; +import { getCurrentUserInfoApiV1AuthMeGet, refreshTokenApiV1AuthRefreshPost } from '@/lib/api/sdk.gen'; // Cookie 操作工具 const setTokenCookie = (token: string) => { @@ -46,6 +46,7 @@ interface AuthProviderProps { export function AuthProvider({ children }: AuthProviderProps) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); + const refreshTimerRef = useRef(null); const login = (userData: User) => { setUser(userData); @@ -58,6 +59,9 @@ export function AuthProvider({ children }: AuthProviderProps) { } setLoading(false); + + // 登录成功后,启动 token 自动刷新定时器 + startTokenRefresh(); }; const logout = () => { @@ -66,12 +70,127 @@ export function AuthProvider({ children }: AuthProviderProps) { removeTokenCookie(); // 清除 cookie setLoading(false); + // 清除定时器 + if (refreshTimerRef.current) { + clearInterval(refreshTimerRef.current); + refreshTimerRef.current = null; + } + // 跳转到登录页 if (typeof window !== 'undefined') { 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 () => { try { @@ -92,11 +211,15 @@ export function AuthProvider({ children }: AuthProviderProps) { if (response.data) { // 更新用户信息(可能包含最新的权限、角色等) - setUser({ + const updatedUserData = { ...userData, ...response.data, // 合并最新的用户信息 - }); + }; + setUser(updatedUserData); console.log('✅ 用户验证成功,最新用户信息:', response.data); + + // 验证成功后,启动 token 自动刷新定时器 + startTokenRefresh(); } else { // Token无效,清除用户信息 console.warn('⚠️ Token验证失败,清除用户信息'); @@ -133,6 +256,14 @@ export function AuthProvider({ children }: AuthProviderProps) { validateUser(); }, []); + // 清理定时器 + React.useEffect(() => { + return () => { + // 组件卸载时清理定时器 + stopTokenRefresh(); + }; + }, []); + const value: AuthContextType = { user, login,