Files
smart-crop-ui/src/components/auth/AuthContext.tsx

176 lines
4.3 KiB
TypeScript

import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { User, AuthState } from '../../types/auth';
import {
getToken,
getUser,
saveToken,
saveUser,
clearAuth,
isTokenExpired,
refreshAuthToken,
generateToken,
} from '../../lib/authStorage';
interface AuthContextType {
authState: AuthState;
login: (user: User) => void;
logout: () => void;
updateUser: (user: User) => void;
checkAuth: () => boolean;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: ReactNode }) {
const [authState, setAuthState] = useState<AuthState>({
isAuthenticated: false,
user: null,
token: null,
refreshToken: null,
});
// 初始化时检查登录状态
useEffect(() => {
const initAuth = async () => {
const token = getToken();
const user = getUser();
if (token && user) {
// 检查token是否过期
if (isTokenExpired()) {
// 尝试刷新token
const refreshed = await refreshAuthToken();
if (refreshed) {
setAuthState({
isAuthenticated: true,
user,
token: refreshed.token,
refreshToken: refreshed.refreshToken,
});
} else {
// 刷新失败,自动使用默认账号登录
await autoLoginWithDefaultAccount();
}
} else {
setAuthState({
isAuthenticated: true,
user,
token,
refreshToken: getToken(),
});
}
} else {
// 没有登录信息,自动使用默认账号登录
await autoLoginWithDefaultAccount();
}
};
// 自动登录默认账号
const autoLoginWithDefaultAccount = async () => {
// 动态导入避免循环依赖
const { validatePasswordLogin } = await import('../../lib/authStorage');
// 使用默认管理员账号自动登录
const result = await validatePasswordLogin('admin', 'admin123', 'AUTO');
if (result.success && result.user) {
const newToken = generateToken();
const newRefreshToken = generateToken();
saveToken(newToken, newRefreshToken);
saveUser(result.user);
setAuthState({
isAuthenticated: true,
user: result.user,
token: newToken,
refreshToken: newRefreshToken,
});
} else {
// 自动登录失败,显示登录页面
setAuthState({
isAuthenticated: false,
user: null,
token: null,
refreshToken: null,
});
}
};
initAuth();
}, []);
// 定期检查token有效性
useEffect(() => {
if (!authState.isAuthenticated) return;
const interval = setInterval(async () => {
if (isTokenExpired()) {
const refreshed = await refreshAuthToken();
if (refreshed) {
setAuthState(prev => ({
...prev,
token: refreshed.token,
refreshToken: refreshed.refreshToken,
}));
} else {
logout();
}
}
}, 5 * 60 * 1000); // 每5分钟检查一次
return () => clearInterval(interval);
}, [authState.isAuthenticated]);
const login = (user: User) => {
const token = generateToken();
const refreshToken = generateToken();
saveToken(token, refreshToken);
saveUser(user);
setAuthState({
isAuthenticated: true,
user,
token,
refreshToken,
});
};
const logout = () => {
clearAuth();
setAuthState({
isAuthenticated: false,
user: null,
token: null,
refreshToken: null,
});
};
const updateUser = (user: User) => {
saveUser(user);
setAuthState(prev => ({
...prev,
user,
}));
};
const checkAuth = (): boolean => {
return authState.isAuthenticated && !isTokenExpired();
};
return (
<AuthContext.Provider value={{ authState, login, logout, updateUser, checkAuth }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
}