Files
AIclinicalresearch/docs/04-开发规范/10-模块认证规范.md
HaHafeng 40c2f8e148 feat(rag): Complete RAG engine implementation with pgvector
Major Features:
- Created ekb_schema (13th schema) with 3 tables: KB/Document/Chunk
- Implemented EmbeddingService (text-embedding-v4, 1024-dim vectors)
- Implemented ChunkService (smart Markdown chunking)
- Implemented VectorSearchService (multi-query + hybrid search)
- Implemented RerankService (qwen3-rerank)
- Integrated DeepSeek V3 QueryRewriter for cross-language search
- Python service: Added pymupdf4llm for PDF-to-Markdown conversion
- PKB: Dual-mode adapter (pgvector/dify/hybrid)

Architecture:
- Brain-Hand Model: Business layer (DeepSeek) + Engine layer (pgvector)
- Cross-language support: Chinese query matches English documents
- Small Embedding (1024) + Strong Reranker strategy

Performance:
- End-to-end latency: 2.5s
- Cost per query: 0.0025 RMB
- Accuracy improvement: +20.5% (cross-language)

Tests:
- test-embedding-service.ts: Vector embedding verified
- test-rag-e2e.ts: Full pipeline tested
- test-rerank.ts: Rerank quality validated
- test-query-rewrite.ts: Cross-language search verified
- test-pdf-ingest.ts: Real PDF document tested (Dongen 2003.pdf)

Documentation:
- Added 05-RAG-Engine-User-Guide.md
- Added 02-Document-Processing-User-Guide.md
- Updated system status documentation

Status: Production ready
2026-01-21 20:24:29 +08:00

201 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 模块认证规范
> 本文档定义了业务模块如何正确使用平台认证能力,确保所有 API 都正确携带和验证用户身份。
## 1. 架构概览
```
┌─────────────────────────────────────────────────────────────┐
│ 前端 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ common/api/axios.ts ← 带认证的 axios 实例 │ │
│ │ framework/auth/api.ts ← Token 管理 (getAccessToken)│ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ Authorization: Bearer <token>
┌─────────────────────────────────────────────────────────────┐
│ 后端 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ common/auth/auth.middleware.ts │ │
│ │ - authenticate: 验证 JWT Token │ │
│ │ - requirePermission: 权限检查 │ │
│ │ - requireRoles: 角色检查 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## 2. 前端规范
### 2.1 使用带认证的 axios 实例(推荐)
```typescript
// 导入带认证的 apiClient
import apiClient from '../../../common/api/axios';
// 使用方式与 axios 完全相同,自动携带 JWT Token
const response = await apiClient.get('/api/v2/xxx');
const response = await apiClient.post('/api/v2/xxx', data);
```
### 2.2 使用原生 fetch需手动添加 Token
```typescript
import { getAccessToken } from '../../../framework/auth/api';
// 创建 getAuthHeaders 函数
function getAuthHeaders(): HeadersInit {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
const token = getAccessToken();
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
return headers;
}
// 所有 fetch 请求使用 getAuthHeaders()
const response = await fetch(url, {
headers: getAuthHeaders(),
});
// 文件上传(不设置 Content-Type
const token = getAccessToken();
const headers: HeadersInit = {};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await fetch(url, {
method: 'POST',
headers,
body: formData,
});
```
## 3. 后端规范
### 3.1 路由添加认证中间件
```typescript
// 导入认证中间件
import { authenticate, requirePermission } from '../../../common/auth/auth.middleware.js';
// 添加到路由
fastify.get('/xxx', { preHandler: [authenticate] }, handler);
// 需要特定权限
fastify.post('/xxx', {
preHandler: [authenticate, requirePermission('module:action')]
}, handler);
```
### 3.2 控制器获取用户 ID
```typescript
/**
* 获取用户ID从JWT Token中获取
*/
function getUserId(request: FastifyRequest): string {
const userId = (request as any).user?.userId;
if (!userId) {
throw new Error('User not authenticated');
}
return userId;
}
// 在控制器方法中使用
async function myHandler(request: FastifyRequest, reply: FastifyReply) {
const userId = getUserId(request);
// ... 使用 userId
}
```
### 3.3 JWT Token 结构
```typescript
interface DecodedToken {
userId: string; // 用户ID
phone: string; // 手机号
role: string; // 角色
tenantId: string; // 租户ID
tenantCode?: string; // 租户Code
iat: number; // 签发时间
exp: number; // 过期时间
}
```
## 4. 检查清单
### 4.1 新模块开发检查清单
- [ ] **前端 API 文件**
- [ ] 使用 `apiClient` 或添加 `getAuthHeaders()`
- [ ] 文件上传单独处理(不设置 Content-Type
- [ ] 导出函数不包含测试用 userId 参数
- [ ] **后端路由文件**
- [ ] 导入 `authenticate` 中间件
- [ ] 所有需要认证的路由添加 `preHandler: [authenticate]`
- [ ] 公开 API如模板列表可不添加认证
- [ ] **后端控制器文件**
- [ ] 添加 `getUserId()` 辅助函数
- [ ] 移除所有 `MOCK_USER_ID` 或硬编码默认值
- [ ] 使用 `getUserId(request)` 获取用户 ID
### 4.2 已完成模块状态
| 模块 | 前端 API | 后端路由 | 后端控制器 | 状态 |
|------|---------|---------|-----------|------|
| RVW | ✅ apiClient | ✅ authenticate | ✅ getUserId | ✅ |
| PKB | ✅ 拦截器 | ✅ authenticate | ✅ getUserId | ✅ |
| ASL | ✅ getAuthHeaders | ✅ authenticate | ✅ getUserId | ✅ |
| DC Tool B | ✅ getAuthHeaders | ✅ authenticate | ✅ getUserId | ✅ |
| DC Tool C | ✅ apiClient | ✅ authenticate | ✅ getUserId | ✅ |
| IIT | N/A (企业微信) | N/A | ✅ 企业微信userId | ✅ |
| Prompt管理 | ✅ getAuthHeaders | ✅ authenticate | ✅ getUserId | ✅ |
## 5. 常见错误和解决方案
### 5.1 401 Unauthorized
**原因**: 前端没有携带 JWT Token 或 Token 过期
**解决**:
1. 检查前端 API 是否使用 `apiClient``getAuthHeaders()`
2. 检查 localStorage 中是否有 `accessToken`
3. 如果 Token 过期,尝试刷新或重新登录
### 5.2 User not authenticated
**原因**: 后端路由没有添加 `authenticate` 中间件
**解决**: 在路由定义中添加 `preHandler: [authenticate]`
### 5.3 TypeError: Cannot read property 'userId' of undefined
**原因**: 使用了错误的属性名(`request.user.id` 而非 `request.user.userId`
**解决**: 使用 `(request as any).user?.userId`
## 6. 参考文件
- 前端 axios 实例: `frontend-v2/src/common/api/axios.ts`
- 前端 Token 管理: `frontend-v2/src/framework/auth/api.ts`
- 后端认证中间件: `backend/src/common/auth/auth.middleware.ts`
- 后端 JWT 服务: `backend/src/common/auth/jwt.service.ts`