forked from 77media/video-flow
372 lines
8.7 KiB
TypeScript
372 lines
8.7 KiB
TypeScript
import { BASE_URL } from "@/api/constants";
|
||
import { post } from "@/api/request";
|
||
|
||
// API配置
|
||
const API_BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || '';
|
||
const JAVA_BASE_URL = process.env.NEXT_PUBLIC_JAVA_URL || '';
|
||
// Token存储键
|
||
const TOKEN_KEY = 'token';
|
||
const USER_KEY = 'currentUser';
|
||
|
||
/**
|
||
* 登录用户
|
||
*/
|
||
export const loginUser = async (email: string, password: string) => {
|
||
try {
|
||
const response = await fetch(`${JAVA_BASE_URL}/api/user/login`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Accept': 'application/json',
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
username: email,
|
||
password: password,
|
||
}),
|
||
});
|
||
|
||
const data = await response.json();
|
||
if(!data.success){
|
||
throw new Error(data.message)
|
||
}
|
||
// 保存token到本地存储
|
||
setToken(data.token);
|
||
|
||
const user = await getUserProfile();
|
||
|
||
return user;
|
||
} catch (error) {
|
||
console.error('Login failed:', error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 获取token
|
||
*/
|
||
export const getToken = (): string | null => {
|
||
if (typeof window === 'undefined') return null;
|
||
return localStorage.getItem(TOKEN_KEY);
|
||
};
|
||
|
||
/**
|
||
* 设置token
|
||
*/
|
||
export const setToken = (token: string) => {
|
||
if (typeof window === 'undefined') return;
|
||
localStorage.setItem(TOKEN_KEY, token);
|
||
};
|
||
|
||
/**
|
||
* 获取当前用户
|
||
*/
|
||
export const getCurrentUser = () => {
|
||
if (typeof window === 'undefined') return null;
|
||
|
||
const userJson = localStorage.getItem(USER_KEY);
|
||
if (!userJson) return null;
|
||
|
||
try {
|
||
return JSON.parse(userJson);
|
||
} catch (error) {
|
||
console.error('Failed to parse user data from storage', error);
|
||
return null;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 设置用户信息
|
||
*/
|
||
export const setUser = (user: any) => {
|
||
if (typeof window === 'undefined') return;
|
||
localStorage.setItem(USER_KEY, JSON.stringify(user));
|
||
};
|
||
|
||
/**
|
||
* 清除认证数据
|
||
*/
|
||
export const clearAuthData = () => {
|
||
if (typeof window === 'undefined') return;
|
||
localStorage.removeItem(TOKEN_KEY);
|
||
localStorage.removeItem(USER_KEY);
|
||
};
|
||
|
||
/**
|
||
* 用户登出
|
||
*/
|
||
export const logoutUser = () => {
|
||
clearAuthData();
|
||
window.location.href = '/login';
|
||
};
|
||
|
||
/**
|
||
* 检查是否已登录
|
||
*/
|
||
export const isAuthenticated = (): boolean => {
|
||
return !!getToken();
|
||
};
|
||
|
||
/**
|
||
* 创建带有token的请求头
|
||
*/
|
||
export const getAuthHeaders = () => {
|
||
const token = getToken();
|
||
return {
|
||
'Accept': 'application/json',
|
||
'Content-Type': 'application/json',
|
||
...(token && { 'X-EASE-ADMIN-TOKEN': token }),
|
||
};
|
||
};
|
||
|
||
/**
|
||
* 带有自动token处理的fetch封装
|
||
*/
|
||
export const authFetch = async (url: string, options: RequestInit = {}) => {
|
||
const token = getToken();
|
||
|
||
if (!token) {
|
||
throw new Error('No token available');
|
||
}
|
||
|
||
const headers = {
|
||
'Accept': 'application/json',
|
||
'Content-Type': 'application/json',
|
||
'X-EASE-ADMIN-TOKEN': token,
|
||
...options.headers,
|
||
};
|
||
|
||
const response = await fetch(url, {
|
||
...options,
|
||
headers,
|
||
});
|
||
|
||
// 检查是否token过期
|
||
if (response.status === 401) {
|
||
const data = await response.json();
|
||
if (data.code === '401') {
|
||
// Token过期,清除本地数据并重定向到登录页
|
||
clearAuthData();
|
||
window.location.href = '/login';
|
||
throw new Error('Token expired');
|
||
}
|
||
}
|
||
|
||
return response;
|
||
};
|
||
|
||
// Google OAuth相关函数保持不变
|
||
const GOOGLE_CLIENT_ID = '1016208801816-qtvcvki2jobmcin1g4e7u4sotr0p8g3u.apps.googleusercontent.com';
|
||
const GOOGLE_REDIRECT_URI = typeof window !== 'undefined'
|
||
? BASE_URL+'/users/oauth/callback'
|
||
: '';
|
||
|
||
/**
|
||
* Initiates Google OAuth authentication flow
|
||
*/
|
||
export const signInWithGoogle = () => {
|
||
const state = generateOAuthState();
|
||
|
||
const params = new URLSearchParams({
|
||
client_id: GOOGLE_CLIENT_ID,
|
||
redirect_uri: GOOGLE_REDIRECT_URI,
|
||
response_type: 'code',
|
||
scope: 'email profile',
|
||
prompt: 'select_account',
|
||
state: state,
|
||
});
|
||
|
||
// Redirect to Google's OAuth endpoint
|
||
window.location.href = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
||
};
|
||
|
||
/**
|
||
* Generates and stores a state parameter for OAuth to prevent CSRF attacks
|
||
*/
|
||
export const generateOAuthState = () => {
|
||
if (typeof window === 'undefined') return '';
|
||
|
||
// Generate a random string for state
|
||
const state = Math.random().toString(36).substring(2, 15);
|
||
|
||
// Store the state in session storage to validate later
|
||
sessionStorage.setItem('oauthState', state);
|
||
|
||
return state;
|
||
};
|
||
|
||
/**
|
||
* Validates the state parameter returned from OAuth to prevent CSRF attacks
|
||
*/
|
||
export const validateOAuthState = (state: string): boolean => {
|
||
if (typeof window === 'undefined') return false;
|
||
|
||
const storedState = sessionStorage.getItem('oauthState');
|
||
|
||
// Clean up the stored state regardless of validity
|
||
sessionStorage.removeItem('oauthState');
|
||
|
||
// Validate that the returned state matches what we stored
|
||
return state === storedState;
|
||
};
|
||
|
||
/**
|
||
* 获取用户信息
|
||
* @returns {Promise<any>} 用户信息对象
|
||
*/
|
||
export const getUserProfile = async (): Promise<any> => {
|
||
// const t = {
|
||
// id: 'fcb6768b6f49449387e6617f75baabc0',
|
||
// userId: 'fcb6768b6f49449387e6617f75baabc0',
|
||
// username: 'gxy',
|
||
// name: 'gxy',
|
||
// email: 'moviflow66@test.com',
|
||
// role: 'USER',
|
||
// isActive: 1,
|
||
// authType: 'LOCAL',
|
||
// lastLogin: new Date(),
|
||
// }
|
||
// setUser(t);
|
||
// return t;
|
||
try {
|
||
const token = getToken();
|
||
if (!token) {
|
||
throw new Error('No token available');
|
||
}
|
||
|
||
const response = await fetch(`${API_BASE_URL}/auth/profile`, {
|
||
method: 'GET',
|
||
headers: {
|
||
'Accept': 'application/json',
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${token}`,
|
||
},
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(response.status.toString());
|
||
}
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.code === 0 && data.successful) {
|
||
// 更新本地存储的用户信息
|
||
const userInfo = {
|
||
id: data.data.user_id,
|
||
userId: data.data.user_id,
|
||
username: data.data.username,
|
||
name: data.data.name,
|
||
email: data.data.email,
|
||
role: data.data.role,
|
||
isActive: data.data.is_active,
|
||
authType: data.data.auth_type,
|
||
lastLogin: data.data.last_login,
|
||
};
|
||
|
||
setUser(userInfo);
|
||
return userInfo;
|
||
} else {
|
||
throw new Error(data.message || 'Failed to get user profile');
|
||
}
|
||
} catch (error) {
|
||
console.error('Get user profile failed:', error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 刷新用户信息
|
||
* @returns {Promise<any>} 最新的用户信息
|
||
*/
|
||
export const refreshUserProfile = async (): Promise<any> => {
|
||
try {
|
||
const profile = await getUserProfile();
|
||
return profile;
|
||
} catch (error) {
|
||
console.error('Refresh user profile failed:', error);
|
||
// 如果刷新失败,返回本地存储的用户信息
|
||
return getCurrentUser();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 检查用户权限
|
||
* @param {string} requiredRole 需要的角色权限
|
||
* @returns {boolean} 是否有权限
|
||
*/
|
||
export const checkUserPermission = (requiredRole: string): boolean => {
|
||
const user = getCurrentUser();
|
||
if (!user || !user.role) {
|
||
return false;
|
||
}
|
||
|
||
// 角色权限等级
|
||
const roleHierarchy = {
|
||
'ADMIN': 3,
|
||
'MODERATOR': 2,
|
||
'USER': 1,
|
||
};
|
||
|
||
const userRoleLevel = roleHierarchy[user.role as keyof typeof roleHierarchy] || 0;
|
||
const requiredRoleLevel = roleHierarchy[requiredRole as keyof typeof roleHierarchy] || 0;
|
||
|
||
return userRoleLevel >= requiredRoleLevel;
|
||
};
|
||
|
||
/**
|
||
* 检查用户是否激活
|
||
* @returns {boolean} 用户是否激活
|
||
*/
|
||
export const isUserActive = (): boolean => {
|
||
const user = getCurrentUser();
|
||
return user?.isActive === 1;
|
||
};
|
||
/**
|
||
* 用户注册
|
||
* @param {Object} params - 注册参数
|
||
* @param {string} params.userName - 用户名
|
||
* @param {string} params.password - 密码
|
||
* @param {string} params.email - 邮箱
|
||
* @param {string} [params.inviteCode] - 邀请码(可选)
|
||
* @returns {Promise<any>} 注册结果
|
||
* @throws {Error} 注册失败时抛出异常
|
||
*/
|
||
export const registerUser = async ({
|
||
userName,
|
||
password,
|
||
email,
|
||
inviteCode,
|
||
}: {
|
||
userName: string;
|
||
password: string;
|
||
email: string;
|
||
inviteCode?: string;
|
||
}): Promise<any> => {
|
||
try {
|
||
const response = await fetch(`${JAVA_BASE_URL}/api/user/register`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Accept': 'application/json',
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
userName,
|
||
password,
|
||
email,
|
||
inviteCode,
|
||
}),
|
||
});
|
||
|
||
const data = await response.json();
|
||
console.log('data', data)
|
||
if(!data.success){
|
||
throw new Error(data.message||data.msg)
|
||
}
|
||
return data as {
|
||
success: boolean;
|
||
};
|
||
} catch (error) {
|
||
console.error('Register failed:', error);
|
||
throw error;
|
||
}
|
||
};
|