# 路由守卫

<cite>
**本文档引用的文件**   
- [permission.ts](file://src/router/guard/permission.ts)
- [userLoginInfo.ts](file://src/router/guard/userLoginInfo.ts)
- [index.ts](file://src/router/index.ts)
- [permission.ts](file://src/hooks/permission.ts)
- [user.ts](file://src/store/modules/user/index.ts)
- [app.ts](file://src/store/modules/app/index.ts)
- [auth.ts](file://src/utils/auth.ts)
- [index.ts](file://src/store/index.ts)
</cite>

## 目录

1. [简介](#简介)
2. [路由守卫机制](#路由守卫机制)
3. [权限控制实现](#权限控制实现)
4. [用户登录信息验证](#用户登录信息验证)
5. [守卫函数执行流程](#守卫函数执行流程)
6. [与状态管理的集成](#与状态管理的集成)
7. [常见问题解决方案](#常见问题解决方案)

## 简介

本文档详细解析kami_frontend项目中的路由守卫机制，涵盖全局前置守卫、全局解析守卫和全局后置守卫的配置与实现。重点阐述权限控制和用户登录信息验证的实现原理，以及路由守卫与状态管理系统的集成方式。

## 路由守卫机制

kami_frontend项目通过Vue Router的全局前置守卫实现了完整的路由控制机制。路由守卫主要分为两个核心模块：权限控制守卫和用户登录信息验证守卫。

```mermaid
graph TD
A[路由跳转] --> B{用户是否已登录?}
B --> |是| C{目标路由是否需要认证?}
B --> |否| D[重定向到登录页]
C --> |是| E{用户是否有权限访问?}
C --> |否| F[允许访问]
E --> |是| G[允许访问]
E --> |否| H[重定向到首个有权限的路由或404]
```

**Diagram sources**

- [index.ts](file://src/router/index.ts#L1-L37)
- [permission.ts](file://src/router/guard/permission.ts#L8-L53)
- [userLoginInfo.ts](file://src/router/guard/userLoginInfo.ts#L4-L49)

**Section sources**

- [index.ts](file://src/router/index.ts#L1-L37)
- [permission.ts](file://src/router/guard/permission.ts#L1-L54)
- [userLoginInfo.ts](file://src/router/guard/userLoginInfo.ts#L1-L50)

## 权限控制实现

权限控制机制通过`permission.ts`文件中的`setupPermissionGuard`函数实现，该函数注册了Vue Router的`beforeEach`全局前置守卫。

### 权限验证逻辑

权限控制的核心逻辑基于用户角色和路由元信息中的角色要求进行匹配。系统支持两种菜单配置模式：静态配置和服务器动态配置。

```mermaid
sequenceDiagram
participant Router as 路由器
participant Guard as 权限守卫
participant Store as 状态管理
participant Permission as 权限钩子
Router->>Guard : 路由跳转请求
Guard->>Store : 获取应用和用户状态
Guard->>Permission : 验证路由权限
Permission->>Permission : 检查requiresAuth和roles
Permission-->>Guard : 返回权限验证结果
alt 菜单来自服务器
Guard->>Store : 检查异步菜单
Guard->>Store : 获取服务器菜单配置
Guard->>Guard : 遍历服务器菜单
Guard-->>Router : 允许或拒绝访问
else 静态菜单
Guard->>Guard : 直接检查权限
Guard-->>Router : 允许或拒绝访问
end
```

**Diagram sources**

- [permission.ts](file://src/router/guard/permission.ts#L8-L53)
- [permission.ts](file://src/hooks/permission.ts#L3-L32)
- [app.ts](file://src/store/modules/app/index.ts#L8-L74)

**Section sources**

- [permission.ts](file://src/router/guard/permission.ts#L8-L53)
- [permission.ts](file://src/hooks/permission.ts#L3-L32)

### 权限匹配规则

权限匹配遵循以下规则：

1. 如果路由没有设置`requiresAuth`元信息，则允许访问
2. 如果路由没有设置`roles`元信息，则允许访问
3. 如果路由的`roles`包含通配符`*`，则允许所有角色访问
4. 如果用户角色包含在路由的`roles`中，则允许访问

```mermaid
flowchart TD
Start([开始]) --> CheckRequiresAuth["检查requiresAuth"]
CheckRequiresAuth --> |false| AllowAccess["允许访问"]
CheckRequiresAuth --> |true| CheckRoles["检查roles"]
CheckRoles --> |undefined| AllowAccess
CheckRoles --> HasRoles
HasRoles --> CheckWildcard["检查是否包含*"]
CheckWildcard --> |true| AllowAccess
CheckWildcard --> |false| CheckUserRole["检查用户角色"]
CheckUserRole --> |匹配| AllowAccess
CheckUserRole --> |不匹配| DenyAccess["拒绝访问"]
AllowAccess --> End([结束])
DenyAccess --> End
```

**Diagram sources**

- [permission.ts](file://src/hooks/permission.ts#L3-L32)

## 用户登录信息验证

用户登录信息验证通过`userLoginInfo.ts`文件中的`setupUserLoginInfoGuard`函数实现，该函数负责验证用户的登录状态。

### 登录状态验证流程

```mermaid
sequenceDiagram
participant Router as 路由器
participant Guard as 登录信息守卫
participant Auth as 认证工具
participant UserStore as 用户状态
Router->>Guard : 路由跳转请求
Guard->>Auth : 检查localStorage中的token
Auth-->>Guard : 返回登录状态
alt 用户已登录且路由需要认证
Guard-->>Router : 允许访问
else 用户未登录
alt 目标为登录页或404页
Guard-->>Router : 允许访问
else 目标需要认证
Guard->>Router : 重定向到登录页并携带重定向参数
end
end
```

**Diagram sources**

- [userLoginInfo.ts](file://src/router/guard/userLoginInfo.ts#L4-L49)
- [auth.ts](file://src/utils/auth.ts#L1-L50)

**Section sources**

- [userLoginInfo.ts](file://src/router/guard/userLoginInfo.ts#L4-L49)
- [auth.ts](file://src/utils/auth.ts#L1-L50)

### 认证工具实现

认证工具`auth.ts`提供了完整的token管理功能，包括：

- `isLogin()`: 检查用户是否已登录
- `getToken()`: 获取当前token
- `setToken(token)`: 设置token
- `clearToken()`: 清除token
- `setTokenFrom(from)`: 设置token来源
- `getTokenFrom()`: 获取token来源

这些工具函数通过localStorage持久化存储用户认证信息。

## 守卫函数执行流程

路由守卫的执行遵循特定的顺序和逻辑，确保在路由跳转前完成所有必要的验证。

### 执行顺序

1. 首先执行用户登录信息验证守卫
2. 然后执行权限控制守卫
3. 最后执行NProgress进度条完成

### 中断逻辑

守卫函数通过调用`next()`函数来控制路由跳转：

- `next()`: 允许继续导航
- `next(false)`: 中断当前导航
- `next(path)`: 重定向到指定路径
- `next(NOT_FOUND)`: 重定向到404页面

当权限验证失败时，系统会尝试找到用户有权限访问的第一个路由，如果找不到则重定向到404页面。

```mermaid
flowchart TD
A[开始路由跳转] --> B[启动NProgress进度条]
B --> C[执行用户登录信息验证]
C --> D{用户已登录?}
D --> |是| E[执行权限控制验证]
D --> |否| F{目标是否为登录页?}
F --> |是| G[允许访问]
F --> |否| H[重定向到登录页]
E --> I{有权限访问?}
I --> |是| J[允许访问]
I --> |否| K[查找首个有权限的路由]
K --> L{找到路由?}
L --> |是| M[重定向到该路由]
L --> |否| N[重定向到404页面]
G --> O[完成NProgress进度条]
H --> O
J --> O
M --> O
N --> O
O --> P[结束]
```

**Diagram sources**

- [userLoginInfo.ts](file://src/router/guard/userLoginInfo.ts#L4-L49)
- [permission.ts](file://src/router/guard/permission.ts#L8-L53)

## 与状态管理的集成

路由守卫与Pinia状态管理系统深度集成，通过store实现用户状态和应用状态的统一管理。

### 状态管理模块

系统使用三个主要的store模块：

- `userStore`: 管理用户信息和角色
- `appStore`: 管理应用设置和服务器菜单
- `tabBarStore`: 管理标签页状态

```mermaid
classDiagram
class userStore {
+name : string
+accountId : string
+role : string
+userInfo : UserState
+switchRoles()
+setInfo(partial)
+resetInfo()
+info()
+login(loginForm)
+logout()
}
class appStore {
+device : string
+theme : string
+hideMenu : boolean
+serverMenu : RouteRecordNormalized[]
+appCurrentSetting : AppState
+appDevice : string
+appAsyncMenus : RouteRecordNormalized[]
+updateSettings(partial)
+toggleTheme(dark)
+toggleDevice(device)
+toggleMenu(value)
+fetchServerMenuConfig()
+clearServerMenu()
}
class tabBarStore {
+cacheTabList : Set[string]
+tagList : TagProps[]
+getTabList() : TagProps[]
+getCacheList() : string[]
+updateTabList(route)
+deleteTag(idx, tag)
+addCache(name)
+deleteCache(tag)
+freshTabList(tags)
+resetTabList()
}
permissionGuard --> userStore : "使用"
permissionGuard --> appStore : "使用"
userLoginInfoGuard --> userStore : "使用"
```

**Diagram sources**

- [user.ts](file://src/store/modules/user/index.ts#L12-L77)
- [app.ts](file://src/store/modules/app/index.ts#L8-L74)
- [index.ts](file://src/store/index.ts#L1-L9)

**Section sources**

- [user.ts](file://src/store/modules/user/index.ts#L1-L80)
- [app.ts](file://src/store/modules/app/index.ts#L1-L77)
- [index.ts](file://src/store/index.ts#L1-L9)

### 状态更新机制

当路由变化时，系统会自动更新相关状态：

1. 用户登录成功后，将token存储到localStorage，并更新userStore中的用户信息
2. 权限验证过程中，从appStore获取服务器菜单配置
3. 路由跳转完成后，更新tabBarStore中的标签页列表

## 常见问题解决方案

### 守卫循环问题

守卫循环通常发生在重定向逻辑不当的情况下。解决方案包括：

1. 在重定向前检查目标路由，避免无限循环
2. 使用白名单机制，确保某些路由（如登录页、404页）始终可访问
3. 在重定向时添加适当的条件判断

### 权限更新不及时问题

当用户角色动态变化时，可能出现权限更新不及时的情况。解决方案包括：

1. 在角色切换后强制刷新路由
2. 监听角色变化事件，及时更新权限状态
3. 在关键操作前重新验证权限

### 异步验证处理

对于需要异步验证的场景，守卫函数支持async/await语法，确保在验证完成前阻止路由跳转：

```typescript
router.beforeEach(async (to, from, next) => {
  // 异步验证逻辑
  const isValid = await validateToken();
  if (isValid) {
    next();
  } else {
    next('/login');
  }
});
```

### 错误跳转处理

在验证过程中发生错误时，应妥善处理并提供友好的用户提示：

```typescript
try {
  await userStore.info();
  next();
} catch (error) {
  await userStore.logout();
  next({
    name: 'login',
    query: {
      redirect: to.name,
      ...to.query
    }
  });
}
```

这些机制共同构成了kami_frontend项目健壮的路由守卫系统，确保了应用的安全性和用户体验。
