video-flow-b/lib/auth.ts
2025-08-28 22:18:30 +08:00

388 lines
9.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
console.log('data', data)
// 保存token到本地存储
setToken(data.token);
const user = await getUserProfile();
return user;
} catch (error) {
console.error('Login failed:', error);
throw error;
}
};
/**
* 鉴权检查
*/
export const checkAuth = async (): Promise<boolean> => {
const token = getToken();
if (!token) {
return false;
}
try {
const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/admin/login/auth`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-EASE-ADMIN-TOKEN': token,
},
});
const data = await response.json();
return true;
// if (data.code === '401' || data.status === 401) {
// // Token无效清除本地存储
// // clearAuthData();
// // return false;
// }
// return data.code === '200' && data.status === 200;
} catch (error) {
console.error('Auth check failed:', error);
return false;
}
};
/**
* 获取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> => {
try {
const token = getToken();
if (!token) {
throw new Error('No token available');
}
const response = await fetch(`${API_BASE_URL}/java-auth/profile`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
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();
return data as {
success: boolean;
};
} catch (error) {
console.error('Register failed:', error);
throw error;
}
};