auth-utils.js 6.17 KB
/**
 * 认证工具文件
 * 用于管理用户认证状态和提供通用的API调用方法
 */

// 全局认证状态
window.AUTH_STATE = {
  isLoggedIn: false,
  token: null,
  userInfo: null,
  theme: null
};

/**
 * 获取认证token
 * @returns {string|null} 认证token或null
 */
function getAuthToken() {
  // 优先从全局变量获取
  if (window.AUTH_TOKEN) {
    return window.AUTH_TOKEN;
  }
  
  // 从localStorage获取
  const token = localStorage.getItem('authToken');
  if (token) {
    window.AUTH_TOKEN = token;
    return token;
  }
  
  return null;
}

/**
 * 检查是否已登录
 * @returns {boolean} 是否已登录
 */
function isLoggedIn() {
  const token = getAuthToken();
  return !!token;
}

/**
 * 获取用户信息
 * @returns {object|null} 用户信息或null
 */
function getUserInfo() {
  // 优先从全局变量获取
  if (window.USER_INFO) {
    return window.USER_INFO;
  }
  
  // 从localStorage获取
  const userInfo = localStorage.getItem('userInfo');
  if (userInfo) {
    try {
      const parsed = JSON.parse(userInfo);
      window.USER_INFO = parsed;
      return parsed;
    } catch (e) {
      console.error('解析用户信息失败:', e);
      return null;
    }
  }
  
  return null;
}

/**
 * 获取用户主题
 * @returns {string|null} 用户主题或null
 */
function getUserTheme() {
  // 优先从全局变量获取
  if (window.USER_THEME) {
    return window.USER_THEME;
  }
  
  // 从localStorage获取
  const theme = localStorage.getItem('userTheme');
  if (theme) {
    window.USER_THEME = theme;
    return theme;
  }
  
  return null;
}

/**
 * 设置认证状态
 * @param {object} data 登录响应数据
 */
function setAuthState(data) {
  if (data && data.token) {
    window.AUTH_TOKEN = data.token;
    localStorage.setItem('authToken', data.token);
    window.AUTH_STATE.isLoggedIn = true;
    window.AUTH_STATE.token = data.token;
    
    console.log('✅ 认证状态已设置');
  }
  
  if (data && data.user) {
    window.USER_INFO = data.user;
    localStorage.setItem('userInfo', JSON.stringify(data.user));
    window.AUTH_STATE.userInfo = data.user;
  }
  
  if (data && data.theme) {
    window.USER_THEME = data.theme;
    localStorage.setItem('userTheme', data.theme);
    window.AUTH_STATE.theme = data.theme;
  }
}

/**
 * 清除认证状态
 */
function clearAuthState() {
  window.AUTH_TOKEN = null;
  window.USER_INFO = null;
  window.USER_THEME = null;
  window.AUTH_STATE.isLoggedIn = false;
  window.AUTH_STATE.token = null;
  window.AUTH_STATE.userInfo = null;
  window.AUTH_STATE.theme = null;
  
  localStorage.removeItem('authToken');
  localStorage.removeItem('userInfo');
  localStorage.removeItem('userTheme');
  
  console.log('✅ 认证状态已清除');
}

/**
 * 带认证的API调用
 * @param {string} url API地址
 * @param {object} options 请求选项
 * @returns {Promise} 响应Promise
 */
async function authenticatedFetch(url, options = {}) {
  const token = getAuthToken();
  
  if (!token) {
    throw new Error('未找到认证token,请重新登录');
  }
  
  // 设置默认headers
  const headers = {
    'Accept': 'application/json',
    'Authorization': token,
    ...options.headers
  };
  
  // 合并请求选项
  const fetchOptions = {
    ...options,
    headers
  };
  
  try {
    const response = await fetch(url, fetchOptions);
    
    // 如果返回401未授权,清除认证状态
    if (response.status === 401) {
      clearAuthState();
      throw new Error('认证已过期,请重新登录');
    }
    
    return response;
  } catch (error) {
    if (error.message.includes('认证已过期')) {
      // 重定向到登录页面
      window.location.href = 'login.html';
    }
    throw error;
  }
}

/**
 * 带认证的POST请求
 * @param {string} url API地址
 * @param {object} data 请求数据
 * @param {object} options 其他选项
 * @returns {Promise} 响应Promise
 */
async function authenticatedPost(url, data, options = {}) {
  const postOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...options.headers
    },
    body: JSON.stringify(data),
    ...options
  };
  
  return authenticatedFetch(url, postOptions);
}

/**
 * 带认证的GET请求
 * @param {string} url API地址
 * @param {object} options 其他选项
 * @returns {Promise} 响应Promise
 */
async function authenticatedGet(url, options = {}) {
  const getOptions = {
    method: 'GET',
    headers: {
      ...options.headers
    },
    ...options
  };
  
  return authenticatedFetch(url, getOptions);
}

/**
 * 检查token是否有效
 * @returns {boolean} token是否有效
 */
function isTokenValid() {
  const token = getAuthToken();
  if (!token) return false;
  
  // 这里可以添加JWT token过期检查逻辑
  // 目前简单返回true,实际项目中应该解析JWT并检查exp字段
  
  return true;
}

/**
 * 初始化认证状态
 * 页面加载时调用,从localStorage恢复认证状态
 */
function initAuthState() {
  const token = localStorage.getItem('authToken');
  const userInfo = localStorage.getItem('userInfo');
  const theme = localStorage.getItem('userTheme');
  
  if (token) {
    window.AUTH_TOKEN = token;
    window.AUTH_STATE.isLoggedIn = true;
    window.AUTH_STATE.token = token;
  }
  
  if (userInfo) {
    try {
      const parsed = JSON.parse(userInfo);
      window.USER_INFO = parsed;
      window.AUTH_STATE.userInfo = parsed;
    } catch (e) {
      console.error('解析用户信息失败:', e);
    }
  }
  
  if (theme) {
    window.USER_THEME = theme;
    window.AUTH_STATE.theme = theme;
  }
  
  console.log('🔐 认证状态已初始化:', {
    isLoggedIn: window.AUTH_STATE.isLoggedIn,
    hasToken: !!window.AUTH_TOKEN,
    hasUserInfo: !!window.USER_INFO,
    theme: window.USER_THEME
  });
}

// 页面加载时自动初始化认证状态
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initAuthState);
} else {
  initAuthState();
}

// 导出到全局作用域
window.AUTH_UTILS = {
  getAuthToken,
  isLoggedIn,
  getUserInfo,
  getUserTheme,
  setAuthState,
  clearAuthState,
  authenticatedFetch,
  authenticatedPost,
  authenticatedGet,
  isTokenValid,
  initAuthState
};

console.log('🔐 认证工具已加载');