auth.js 3.78 KB
/*
 * @Date: 2025-03-20 21:11:31
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-03-24 01:10:13
 * @FilePath: /mlaj/src/contexts/auth.js
 * @Description: 认证上下文管理模块,提供用户认证状态管理、登录登出功能
 */

// 导入Vue的组合式API相关函数
import { ref, provide, inject, onMounted } from 'vue'

// 创建认证上下文的Symbol key,用于provide/inject依赖注入
// 使用Symbol确保key的唯一性,避免命名冲突
const authKey = Symbol('auth')

/**
 * 提供认证功能的组合式函数
 * 该函数创建并提供认证上下文,包含:
 * 1. 用户状态管理(currentUser)
 * 2. 加载状态管理(loading)
 * 3. 登录登出功能
 * 4. Token过期检查
 */
export function provideAuth() {
  // 当前用户状态,初始为null表示未登录
  const currentUser = ref(null)
  // 加载状态标志,用于控制加载动画等UI展示
  const loading = ref(true)

  /**
   * 检查登录token是否过期
   * @returns {boolean} true表示token有效,false表示token已过期
   */
  const checkTokenExpiration = () => {
    const loginTimestamp = localStorage.getItem('loginTimestamp')
    if (loginTimestamp) {
      const now = Date.now()
      const diff = now - parseInt(loginTimestamp)
      // 检查是否超过24小时(24 * 60 * 60 * 1000 毫秒)
      if (diff > 24 * 60 * 60 * 1000) {
        // token过期,清理登录状态并返回false
        logout()
        return false
      }
    }
    return true
  }

  /**
   * 组件挂载时初始化用户状态
   * 1. 从localStorage读取保存的用户信息
   * 2. 检查token是否过期
   * 3. 恢复用户状态或保持登出状态
   */
  onMounted(() => {
    const savedUser = localStorage.getItem('currentUser')
    if (savedUser) {
      // 检查token是否有效,有效则恢复用户状态
      if (checkTokenExpiration()) {
        currentUser.value = JSON.parse(savedUser)
      }
    }
    // 初始化完成,关闭加载状态
    loading.value = false
  })

  /**
   * 用户登录函数
   * @param {Object} userData - 用户数据对象,包含用户基本信息
   * @returns {boolean} 登录是否成功
   */
  const login = (userData) => {
    // 更新当前用户状态
    currentUser.value = userData
    if (currentUser.value) {
      try {
        // 持久化存储用户信息和登录时间戳
        localStorage.setItem('currentUser', JSON.stringify(userData))
        localStorage.setItem('loginTimestamp', Date.now().toString())
      } catch (error) {
        console.error('Failed to save user data to localStorage:', error)
      }
    }
    return true
  }

  /**
   * 用户登出函数
   * 清理用户状态和本地存储的认证信息
   */
  const logout = () => {
    // 清空当前用户状态
    currentUser.value = null
    // 清理本地存储的用户信息和登录时间戳
    localStorage.removeItem('currentUser')
    localStorage.removeItem('loginTimestamp')
  }

  /**
   * 提供认证上下文给子组件使用
   * 包含:
   * - currentUser: 当前用户状态
   * - loading: 加载状态
   * - login: 登录函数
   * - logout: 登出函数
   */
  provide(authKey, {
    currentUser,
    loading,
    login,
    logout
  })

  // 返回认证相关的状态和方法,供组件直接使用
  return {
    currentUser,
    loading,
    login,
    logout
  }
}

/**
 * 在子组件中使用认证功能的组合式函数
 * @returns {Object} 认证上下文对象,包含用户状态和认证方法
 * @throws {Error} 如果在provideAuth范围外使用则抛出错误
 */
export function useAuth() {
  // 注入认证上下文
  const auth = inject(authKey)
  // 确保在provideAuth的范围内使用
  if (!auth) {
    throw new Error('useAuth 必须在 provideAuth 的范围内使用')
  }
  return auth
}