fenghuo/apps/web/providers/auth-provider.tsx

131 lines
3.0 KiB
TypeScript

'use client';
import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';
import { User } from 'oidc-client-ts';
import { userManager } from '@/lib/oidc-config';
interface AuthContextType {
user: User | null;
isLoading: boolean;
isAuthenticated: boolean;
login: () => Promise<void>;
logout: () => Promise<void>;
error: string | null;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export const useAuth = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth必须在AuthProvider内部使用');
}
return context;
};
interface AuthProviderProps {
children: ReactNode;
}
export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const isAuthenticated = !!user && !user.expired;
useEffect(() => {
if (!userManager) return;
const initAuth = async () => {
try {
setIsLoading(true);
const currentUser = await userManager.getUser();
setUser(currentUser);
} catch (err) {
console.error('初始化认证失败:', err);
setError('认证初始化失败');
} finally {
setIsLoading(false);
}
};
initAuth();
// 监听用户状态变化
const handleUserLoaded = (user: User) => {
setUser(user);
setError(null);
};
const handleUserUnloaded = () => {
setUser(null);
};
const handleAccessTokenExpired = () => {
setUser(null);
setError('访问令牌已过期');
};
const handleSilentRenewError = (error: Error) => {
console.error('静默续约失败:', error);
setError('令牌续约失败');
};
userManager.events.addUserLoaded(handleUserLoaded);
userManager.events.addUserUnloaded(handleUserUnloaded);
userManager.events.addAccessTokenExpired(handleAccessTokenExpired);
userManager.events.addSilentRenewError(handleSilentRenewError);
return () => {
if (userManager) {
userManager.events.removeUserLoaded(handleUserLoaded);
userManager.events.removeUserUnloaded(handleUserUnloaded);
userManager.events.removeAccessTokenExpired(handleAccessTokenExpired);
userManager.events.removeSilentRenewError(handleSilentRenewError);
}
};
}, []);
const login = async () => {
if (!userManager) {
setError('用户管理器未初始化');
return;
}
try {
setError(null);
await userManager.signinRedirect();
} catch (err) {
console.error('登录失败:', err);
setError('登录失败');
}
};
const logout = async () => {
if (!userManager) {
setError('用户管理器未初始化');
return;
}
try {
setError(null);
await userManager.signoutRedirect();
} catch (err) {
console.error('登出失败:', err);
setError('登出失败');
}
};
const value: AuthContextType = {
user,
isLoading,
isAuthenticated,
login,
logout,
error,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};