147 lines
5.3 KiB
TypeScript
147 lines
5.3 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());
|
|
if (Platform.OS === 'web') {
|
|
localStorage.setItem('user', "");
|
|
localStorage.setItem('token', "");
|
|
} else {
|
|
SecureStore.setItemAsync('user', "");
|
|
SecureStore.setItemAsync('token', "");
|
|
}
|
|
// 触发事件通知
|
|
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;
|
|
}; |