memowake-front/contexts/auth-context.tsx
2025-07-07 13:42:11 +08:00

141 lines
5.0 KiB
TypeScript

import { clearCredentials, selectCurrentToken, selectCurrentUser, setCredentials } from '@/features/auth/authSlice';
import { EVENT_TYPES, eventEmitter } from '@/lib/event-util';
import { fetchApi, refreshAuthToken } from '@/lib/server-api-util';
import { store } from '@/store';
import { User } from '@/types/user';
import * as SecureStore from 'expo-secure-store';
import React, { createContext, ReactNode, useContext, useEffect } from 'react';
import { Platform } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
interface AuthContextType {
user: User | null;
login: (user: User, jwt: string) => void;
logout: () => void;
jwt: string | null;
isGuester: () => Promise<boolean>;
isFormalUser: (userMessage: User | null) => boolean;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const dispatch = useDispatch();
const user = useSelector(selectCurrentUser);
const jwt = useSelector(selectCurrentToken);
useEffect(() => {
// 检查 Redux store 中是否已有 token
const refreshTokenAction = async () => {
let token = store.getState().auth.token;
if (Platform.OS === 'web') {
token = localStorage.getItem('token') || "";
} else {
await SecureStore.getItemAsync('token').then((token) => {
token = token || "";
})
}
if (token) {
// 验证当前 token 是否有效
fetchApi('/user/identity-check', {}, false)
.catch(async (error) => {
// console.error("JWT validation failed, attempting to refresh token...");
try {
// 尝试刷新 token
await refreshAuthToken("Token expired");
// console.log("Token refreshed successfully");
// Token 刷新成功,不需要做其他操作
} catch (refreshError) {
// 刷新 token 失败,才进行登出操作
// console.error("Token refresh failed, logging out", refreshError);
logout();
}
});
} else {
try {
// 尝试刷新 token
await refreshAuthToken("Token expired");
// console.log("Token refreshed successfully");
// Token 刷新成功,不需要做其他操作
} catch (refreshError) {
// 刷新 token 失败,才进行登出操作
// console.error("Token refresh failed, logging out", refreshError);
logout();
}
}
}
refreshTokenAction();
}, [dispatch]);
const login = (newUser: User, newJwt: string) => {
// 更新 Redux store
dispatch(setCredentials({
user: newUser,
token: newJwt
}));
// 判断运行环境是web则存在localstorage或者expo-secure-store中
if (Platform.OS === 'web') {
localStorage.setItem('user', JSON.stringify(newUser));
localStorage.setItem('token', newJwt);
} else {
SecureStore.setItemAsync('user', JSON.stringify(newUser));
SecureStore.setItemAsync('token', newJwt);
}
// 触发事件通知
eventEmitter.emit(EVENT_TYPES.USER_INFO_UPDATED, newUser);
};
const logout = () => {
// 清除 Redux store 中的认证信息
dispatch(clearCredentials());
// 触发事件通知
eventEmitter.emit(EVENT_TYPES.USER_INFO_UPDATED, null);
};
// 判断是否是游客身份
const isGuester = async () => {
// 调用接口判断是否是游客
try {
await fetchApi(`/iam/identity-check`, {
method: 'POST',
}, false);
user?.email === ""
return false
} catch (error) {
return true;
}
}
// 判断是否是正式用户 手机号注册和email注册都为正式用户
const isFormalUser = (userMessage: User | null) => {
if (userMessage?.account) {
if (userMessage?.account?.includes("@")) {
return true
} else if (/^1[3-9]\d{9}$/.test(userMessage?.account)) {
return true
} else {
return false
}
}
// 没有用户信息
return false
}
return (
<AuthContext.Provider value={{ user, login, logout, jwt, isGuester, isFormalUser }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};