coder-common-thin-frontend/doc/登录鉴权系统文档.md
2025-07-04 15:08:19 +08:00

6.4 KiB
Raw Blame History

Nova Admin 登录鉴权系统文档

概述

Nova Admin 采用基于 JWT Token 的登录鉴权机制,通过 Pinia Store 管理认证状态,结合路由守卫实现完整的身份验证和访问控制。

🏗️ 架构设计

核心组件

  1. 认证状态管理 (src/store/auth.ts)
  2. 路由守卫 (src/router/guard.ts)
  3. 登录页面 (src/views/login/)
  4. API 接口 (src/service/api/login.ts)
  5. 本地存储工具 (src/utils/storage.ts)

🔐 认证流程

1. 登录流程

sequenceDiagram
    participant U as 用户
    participant L as 登录页面
    participant A as AuthStore
    participant API as 后端API
    participant R as RouteStore
    participant Router as 路由系统

    U->>L: 输入用户名密码
    L->>A: authStore.login(username, password)
    A->>API: fetchLogin(credentials)
    API-->>A: 返回用户信息和Token
    A->>A: 保存Token和用户信息到localStorage
    A->>R: routeStore.initAuthRoute()
    R->>R: 初始化用户路由和菜单
    A->>Router: 重定向到首页或redirect页面

2. 登出流程

sequenceDiagram
    participant U as 用户
    participant A as AuthStore
    participant R as RouteStore
    participant T as TabStore
    participant Router as 路由系统

    U->>A: authStore.logout()
    A->>A: 清除本地存储(Token, userInfo)
    A->>R: routeStore.resetRouteStore()
    A->>T: tabStore.clearAllTabs()
    A->>A: 重置Store状态
    A->>Router: 重定向到登录页

📁 文件结构详解

AuthStore (src/store/auth.ts)

负责管理用户认证状态和相关操作:

状态管理

interface AuthStatus {
  userInfo: Api.Login.Info | null  // 用户信息
  token: string                    // 访问令牌
}

核心方法

  • login(userName, password): 执行登录操作
  • logout(): 执行登出操作
  • handleLoginInfo(data): 处理登录成功后的数据
  • clearAuthStorage(): 清除本地认证存储

计算属性

  • isLogin: 基于 token 判断用户是否已登录

登录页面组件

主要文件

  • src/views/login/index.vue - 登录页面容器
  • src/views/login/components/Login/index.vue - 登录表单组件
  • src/views/login/components/Register/index.vue - 注册组件
  • src/views/login/components/ResetPwd/index.vue - 重置密码组件

登录表单特性

  • 表单验证(用户名和密码必填)
  • 记住密码功能
  • 加载状态提示
  • 国际化支持

API 接口 (src/service/api/login.ts)

核心接口

// 用户登录
fetchLogin(data: { userName: string, password: string })

// 刷新Token
fetchUpdateToken(data: any)

// 获取用户路由
fetchUserRoutes(params: { id: number })

🛡️ 数据存储

localStorage 存储项

键名 说明 数据类型
accessToken 访问令牌 string
refreshToken 刷新令牌 string
userInfo 用户信息 Api.Login.Info
loginAccount 记住的登录账号 {account: string, pwd: string}

用户信息结构

interface Api.Login.Info {
  accessToken: string
  refreshToken: string
  id: number
  userName: string
  role: Entity.RoleType[]  // 用户角色数组
  // ... 其他用户信息
}

🔒 安全机制

Token 管理

  1. 双Token机制

    • accessToken: 用于API请求认证
    • refreshToken: 用于刷新访问令牌
  2. Token 存储

    • 使用 localStorage 持久化存储
    • 页面刷新后自动恢复登录状态
  3. Token 验证

    • 路由守卫检查 Token 有效性
    • API 请求自动携带 Token

密码安全

  1. 前端验证

    • 必填验证
    • 格式验证(可扩展)
  2. 后端安全

    • 密码加密存储(由后端实现)
    • 登录失败次数限制(由后端实现)

🚦 路由保护

认证检查

路由守卫在 beforeEach 钩子中执行认证检查:

// 判断有无TOKEN,登录鉴权
const isLogin = Boolean(local.get('accessToken'))

if (to.meta.requiresAuth === true && !isLogin) {
  const redirect = to.name === '404' ? undefined : to.fullPath
  next({ path: '/login', query: { redirect } })
  return
}

重定向机制

  1. 未登录访问受保护路由: 重定向到登录页,并保存原始路由
  2. 登录成功: 重定向到原始路由或默认首页
  3. 已登录访问登录页: 重定向到首页

🛠️ 开发指南

添加新的认证检查

  1. 在路由元信息中设置认证要求:
{
  path: '/protected',
  meta: {
    requiresAuth: true  // 需要登录
  }
}
  1. 在组件中检查登录状态:
import { useAuthStore } from '@/store'

const authStore = useAuthStore()
if (!authStore.isLogin) {
  // 处理未登录状态
}

自定义登录逻辑

可以通过扩展 AuthStorelogin 方法来实现自定义登录逻辑:

// 扩展登录验证
async login(userName: string, password: string, captcha?: string) {
  try {
    // 添加验证码验证
    if (this.needCaptcha && !captcha) {
      throw new Error('需要验证码')
    }

    const { isSuccess, data } = await fetchLogin({
      userName,
      password,
      captcha
    })

    if (!isSuccess) return
    await this.handleLoginInfo(data)
  } catch (e) {
    console.warn('[Login Error]:', e)
  }
}

🔧 配置项

环境变量

  • VITE_ROUTE_LOAD_MODE: 路由加载模式static/dynamic
  • VITE_HOME_PATH: 登录成功后的默认首页路径

默认配置

// 默认登录账号(开发环境)
const formValue = ref({
  account: 'admin',
  pwd: '123456',
})

🚨 常见问题

1. Token 过期处理

系统会在请求拦截器中自动处理 Token 过期:

  • 检测到 Token 过期
  • 自动调用刷新 Token 接口
  • 重新发送原始请求

2. 路由初始化时机

确保在路由守卫中正确初始化路由:

if (!routeStore.isInitAuthRoute) {
  await routeStore.initAuthRoute()
  // 处理 404 重新导航
  if (to.name === '404') {
    next({ path: to.fullPath, replace: true })
    return
  }
}

3. 登录状态丢失

检查以下几点:

  • localStorage 是否被清除
  • Token 是否过期
  • 网络请求是否正常

📚 相关文档