forked from 77media/video-flow
252 lines
5.7 KiB
TypeScript
252 lines
5.7 KiB
TypeScript
import { BASE_URL } from "@/api/constants";
|
||
|
||
// API配置
|
||
const API_BASE_URL = 'https://77.api.qikongjian.com';
|
||
|
||
// Token存储键
|
||
const TOKEN_KEY = 'X-EASE-ADMIN-TOKEN';
|
||
const USER_KEY = 'currentUser';
|
||
|
||
/**
|
||
* 登录用户
|
||
*/
|
||
export const loginUser = async (email: string, password: string) => {
|
||
try {
|
||
const response = await fetch(`${API_BASE_URL}/admin/login/signIn`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Accept': 'application/json',
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
userName: email,
|
||
password: password,
|
||
}),
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.code === '200' && data.status === 200) {
|
||
// 保存token到本地存储
|
||
setToken(data.body.token);
|
||
|
||
// 保存用户信息
|
||
const user = {
|
||
id: data.body.userId,
|
||
name: data.body.userName,
|
||
email: email,
|
||
token: data.body.token,
|
||
};
|
||
setUser(user);
|
||
|
||
return user;
|
||
} else {
|
||
throw new Error(data.msg || '登录失败');
|
||
}
|
||
} 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(`${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();
|
||
|
||
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;
|
||
}; |