289 lines
6.4 KiB
Markdown
289 lines
6.4 KiB
Markdown
# 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. 登录流程
|
||
|
||
```mermaid
|
||
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. 登出流程
|
||
|
||
```mermaid
|
||
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`)
|
||
|
||
负责管理用户认证状态和相关操作:
|
||
|
||
#### 状态管理
|
||
|
||
```typescript
|
||
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`)
|
||
|
||
#### 核心接口
|
||
|
||
```typescript
|
||
// 用户登录
|
||
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} |
|
||
|
||
### 用户信息结构
|
||
|
||
```typescript
|
||
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` 钩子中执行认证检查:
|
||
|
||
```typescript
|
||
// 判断有无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. **在路由元信息中设置认证要求**:
|
||
```typescript
|
||
{
|
||
path: '/protected',
|
||
meta: {
|
||
requiresAuth: true // 需要登录
|
||
}
|
||
}
|
||
```
|
||
|
||
2. **在组件中检查登录状态**:
|
||
```typescript
|
||
import { useAuthStore } from '@/store'
|
||
|
||
const authStore = useAuthStore()
|
||
if (!authStore.isLogin) {
|
||
// 处理未登录状态
|
||
}
|
||
```
|
||
|
||
### 自定义登录逻辑
|
||
|
||
可以通过扩展 `AuthStore` 的 `login` 方法来实现自定义登录逻辑:
|
||
|
||
```typescript
|
||
// 扩展登录验证
|
||
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`: 登录成功后的默认首页路径
|
||
|
||
### 默认配置
|
||
|
||
```typescript
|
||
// 默认登录账号(开发环境)
|
||
const formValue = ref({
|
||
account: 'admin',
|
||
pwd: '123456',
|
||
})
|
||
```
|
||
|
||
## 🚨 常见问题
|
||
|
||
### 1. Token 过期处理
|
||
|
||
系统会在请求拦截器中自动处理 Token 过期:
|
||
- 检测到 Token 过期
|
||
- 自动调用刷新 Token 接口
|
||
- 重新发送原始请求
|
||
|
||
### 2. 路由初始化时机
|
||
|
||
确保在路由守卫中正确初始化路由:
|
||
```typescript
|
||
if (!routeStore.isInitAuthRoute) {
|
||
await routeStore.initAuthRoute()
|
||
// 处理 404 重新导航
|
||
if (to.name === '404') {
|
||
next({ path: to.fullPath, replace: true })
|
||
return
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 登录状态丢失
|
||
|
||
检查以下几点:
|
||
- localStorage 是否被清除
|
||
- Token 是否过期
|
||
- 网络请求是否正常
|
||
|
||
## 📚 相关文档
|
||
|
||
- [权限系统文档](./权限管理系统文档)
|
||
- [路由系统文档](./路由管理系统文档)
|
||
- [整体架构文档](./整体架构文档)
|