# API级别访问控制

<cite>
**本文档中引用的文件**  
- [interceptor.ts](file://src/api/interceptor.ts)
- [auth.ts](file://src/utils/auth.ts)
- [base.ts](file://src/api/generated/base.ts)
- [api.ts](file://src/api/generated/api.ts)
</cite>

## 目录

1. [简介](#简介)
2. [API请求拦截器实现机制](#api请求拦截器实现机制)
3. [API响应拦截器与权限控制](#api响应拦截器与权限控制)
4. [API权限令牌管理机制](#api权限令牌管理机制)
5. [API访问控制配置示例](#api访问控制配置示例)
6. [开发者最佳实践](#开发者最佳实践)
7. [常见问题解决方案](#常见问题解决方案)
8. [结论](#结论)

## 简介

本文档详细阐述了kami_frontend项目中API级别访问控制的实现机制。系统通过Axios拦截器实现了完整的认证与权限控制流程，包括请求前自动注入认证信息、响应时统一处理权限异常、令牌自动刷新等功能。该机制确保了前端与后端API通信的安全性与可靠性，为不同API端点提供了灵活的权限控制策略。

## API请求拦截器实现机制

API请求拦截器在请求发送前自动添加认证信息和权限标识，确保每个请求都携带有效的身份凭证。拦截器通过读取本地存储的令牌信息，并将其注入到请求头中。

```mermaid
sequenceDiagram
participant 前端应用
participant 请求拦截器
participant 后端API
前端应用->>请求拦截器 : 发起API请求
请求拦截器->>请求拦截器 : 读取本地Token
请求拦截器->>请求拦截器 : 检查Token有效性
请求拦截器->>请求拦截器 : 添加Authorization头
请求拦截器->>请求拦截器 : 添加tokenFrom标识
请求拦截器->>后端API : 发送带认证信息的请求
后端API-->>前端应用 : 返回响应
```

**拦截器源码流程：**

1. 从localStorage获取当前用户的认证令牌
2. 检查令牌是否存在且有效
3. 在请求头中添加`Authorization: Bearer <token>`字段
4. 添加`tokenFrom`头部标识令牌来源（如iframe或登录）
5. 继续请求流程

**API请求拦截器作用：**

- 自动化认证：无需在每个API调用中手动添加认证信息
- 统一管理：集中处理所有请求的认证逻辑
- 来源标识：通过`tokenFrom`头部区分不同场景下的令牌来源
- 请求预处理：对请求参数进行统一序列化处理

**Diagram sources**

- [interceptor.ts](file://src/api/interceptor.ts#L20-L35)

**Section sources**

- [interceptor.ts](file://src/api/interceptor.ts#L20-L35)
- [auth.ts](file://src/utils/auth.ts#L7-L15)

## API响应拦截器与权限控制

API响应拦截器负责处理服务器返回的响应，特别是对权限相关的状态码进行统一处理，提供一致的用户体验。

```mermaid
flowchart TD
A[接收API响应] --> B{检查refresh-token}
B --> |存在| C[更新本地Token]
B --> |不存在| D{检查响应类型}
D --> |二进制文件| E[直接返回响应]
D --> |JSON数据| F{检查业务状态码}
F --> |code=0| G[返回数据]
F --> |code≠0| H{检查错误码}
H --> |5001,5002,5003| I[显示登录过期模态框]
H --> |其他错误| J[显示错误消息]
I --> K[用户选择操作]
K --> L[重新登录或刷新页面]
```

**响应拦截器核心功能：**

- **令牌刷新**：当响应头包含`refresh-token`时，自动更新本地存储的令牌
- **二进制文件处理**：识别下载类响应（如Excel、ZIP文件），避免数据解析错误
- **统一错误处理**：对非200状态码的响应进行集中错误提示
- **登录过期处理**：检测到5001、5002、5003等特定错误码时，提示用户登录已过期

**权限相关状态码处理策略：**

- **401未授权**：自动触发重新登录流程
- **403禁止访问**：根据用户角色显示相应提示
- **5001/5002/5003**：明确标识为登录过期，提供重新登录选项
- 其他错误码：统一显示错误消息，持续5秒

当检测到登录过期时，系统会弹出模态框，提供"重新登录"选项，用户确认后将清除本地认证信息并刷新页面，引导用户重新登录。

**Diagram sources**

- [interceptor.ts](file://src/api/interceptor.ts#L38-L78)

**Section sources**

- [interceptor.ts](file://src/api/interceptor.ts#L38-L78)
- [auth.ts](file://src/utils/auth.ts#L17-L25)

## API权限令牌管理机制

系统采用基于localStorage的令牌管理机制，实现了令牌的获取、存储、读取和清除等完整生命周期管理。

```mermaid
classDiagram
class TokenManager {
+TOKEN_KEY : string
+TOKEN_FROM_KEY : string
+isLogin() : boolean
+getToken() : string | null
+setToken(token : string) : void
+clearToken() : void
+getTokenFrom() : string | null
+setTokenFrom(from : string) : void
+checkTokenFromIframe() : boolean
+checkTokenFromLogin() : boolean
+clearTokenFrom() : void
}
class RequestInterceptor {
+axios.defaults.baseURL
+axios.interceptors.request.use()
}
class ResponseInterceptor {
+axios.interceptors.response.use()
}
TokenManager --> RequestInterceptor : "提供Token"
TokenManager --> ResponseInterceptor : "更新Token"
RequestInterceptor --> ResponseInterceptor : "完整请求响应周期"
```

**令牌存储策略：**

- **存储位置**：使用浏览器的localStorage进行持久化存储
- **主令牌键名**：`token`（对应常量TOKEN_KEY）
- **来源标识键名**：`tokenFrom`（对应常量TOKEN_FROM_KEY）
- **存储内容**：JWT格式的认证令牌字符串

**令牌操作方法：**

- `getToken()`：获取当前认证令牌
- `setToken(token)`：设置新的认证令牌
- `clearToken()`：清除认证令牌及相关信息
- `getTokenFrom()`：获取令牌来源标识
- `setTokenFrom(from)`：设置令牌来源标识

**令牌来源标识：**

- `iframe`：来自iframe嵌入场景
- `login`：来自正常登录流程
- 其他：默认来源

系统通过`checkTokenFromIframe()`和`checkTokenFromLogin()`等工具方法，可以根据令牌来源执行不同的业务逻辑，实现场景化的权限控制。

**Diagram sources**

- [auth.ts](file://src/utils/auth.ts#L0-L50)
- [interceptor.ts](file://src/api/interceptor.ts#L0-L89)

**Section sources**

- [auth.ts](file://src/utils/auth.ts#L0-L50)

## API访问控制配置示例

虽然项目中没有显式的API权限配置文件，但通过拦截器和工具函数的组合，实现了灵活的访问控制配置。

### 基础API配置

```mermaid
flowchart LR
A[API基础配置] --> B[设置基础URL]
A --> C[配置参数序列化]
A --> D[注册拦截器]
B --> E[从环境变量读取VITE_API_BASE_URL]
C --> F[使用query-string库序列化数组参数]
D --> G[请求拦截器]
D --> H[响应拦截器]
```

**环境变量配置：**

```typescript
if (import.meta.env.VITE_API_BASE_URL) {
  axios.defaults.baseURL = import.meta.env.VITE_API_BASE_URL;
}
```

**参数序列化配置：**

```typescript
axios.defaults.paramsSerializer = params => {
  return qs.stringify(params, { arrayFormat: 'bracket' });
};
```

### 特殊端点配置

对于需要特殊处理的API端点，系统通过在调用时指定额外配置来实现：

**文件下载API配置：**

```typescript
const response = await axios.get<Blob>('/api/download', {
  responseType: 'blob'
});
```

**自定义参数序列化：**

```typescript
const response = await axios.get('/api/search', {
  params: { ids: [1, 2, 3] },
  paramsSerializer: obj => {
    return qs.stringify(obj);
  }
});
```

这些配置确保了API调用的一致性和可靠性，特别是在处理复杂参数和文件下载场景时。

**Section sources**

- [interceptor.ts](file://src/api/interceptor.ts#L15-L19)
- [apple-card-recharge-history.ts](file://src/api/apple-card-recharge-history.ts#L108-L117)

## 开发者最佳实践

为确保API访问控制的正确实施，开发者应遵循以下最佳实践：

### 请求重试机制

当遇到网络波动或临时性错误时，建议实现智能重试机制：

```mermaid
flowchart TD
A[API请求失败] --> B{错误类型}
B --> |网络错误| C[等待随机时间]
B --> |超时| C
B --> |5xx错误| C
B --> |其他| D[直接报错]
C --> E[重试次数<最大值]
E --> |是| F[执行重试]
E --> |否| G[显示最终错误]
F --> A
```

### 权限失效处理

遵循系统内置的权限失效处理流程，不要绕过拦截器的统一处理机制：

1. 依赖拦截器自动检测5001-5003错误码
2. 不要捕获并静默处理认证相关错误
3. 尊重用户在过期提示中的选择

### 跨域请求权限验证

对于跨域请求，确保：

- 服务器正确配置CORS策略
- 携带必要的认证头部
- 处理预检请求（OPTIONS）的权限验证

### 敏感API额外保护

对敏感操作API实施额外保护措施：

- 增加二次确认对话框
- 记录操作日志
- 限制频繁操作
- 实施IP白名单验证（后端实现）

**Section sources**

- [interceptor.ts](file://src/api/interceptor.ts#L60-L75)
- [merchant-list.ts](file://src/api/merchant-list.ts)

## 常见问题解决方案

### 令牌过期处理

**问题现象**：用户操作过程中突然跳转到登录页或提示登录过期。

**解决方案**：

1. 系统已通过响应拦截器自动处理5001-5003错误码
2. 用户在模态框中选择"重新登录"
3. 系统调用`useUserStore().logout()`清除状态
4. 页面刷新，重新加载应用

**预防措施**：

- 实现令牌刷新机制（已在拦截器中实现）
- 在令牌即将过期前主动刷新
- 保持用户活跃状态检测

### 并发请求的权限控制

**问题现象**：多个并发请求中，部分请求因权限问题失败。

**解决方案**：

- 所有请求共享同一认证令牌
- 通过拦截器确保每个请求都携带最新令牌
- 当首个请求触发令牌刷新时，后续请求使用新令牌

**实现机制**：

```mermaid
sequenceDiagram
请求1->>后端 : 携带旧Token
请求2->>后端 : 携带旧Token
后端-->>请求1 : 返回新refresh-token
拦截器->>localStorage : 更新Token
后端-->>请求2 : 因Token失效返回401
重试机制->>后端 : 使用新Token重试请求2
后端-->>重试机制 : 成功响应
```

### 跨域请求的权限验证

**问题现象**：跨域API请求被浏览器阻止或权限验证失败。

**解决方案**：

1. 确保后端API正确配置CORS头部
2. 前端请求中设置`withCredentials: true`（如需要）
3. 在预检请求（OPTIONS）中包含必要的认证信息
4. 使用iframe场景下的特殊令牌来源标识

**配置示例**：

```typescript
// 对于需要凭证的跨域请求
axios.create({
  withCredentials: true
});
```

系统通过`tokenFrom`标识区分iframe场景，确保跨域嵌入时的权限验证正常工作。

**Section sources**

- [interceptor.ts](file://src/api/interceptor.ts)
- [auth.ts](file://src/utils/auth.ts)
- [router/routes/modules/iframe.ts](file://src/router/routes/modules/iframe.ts)

## 结论

kami_frontend项目的API级别访问控制机制通过Axios拦截器实现了完整的认证与权限管理流程。系统采用localStorage存储认证令牌，通过请求拦截器自动注入认证信息，响应拦截器统一处理权限异常，并提供了灵活的令牌管理机制。该设计确保了API通信的安全性，为不同场景提供了适当的权限控制策略，同时为开发者提供了清晰的使用模式和最佳实践指导。整体架构合理，实现了安全性与可用性的平衡。
