重构Dify客户端:改为通过FastAPI代理并使用JWT认证

主要变更:
- 修改 dify-client.server.ts 使用 JWT 认证通过 FastAPI 后端代理访问 Dify API
- 所有 Dify API 路由(chat-messages, parameters, conversations, messages)添加 JWT 获取和传递逻辑
- API_URL 从直连 Dify 改为 FastAPI 后端的 /dify 路由
- 增强 JWT 认证失败的错误处理(返回401状态码)
- 添加详细的日志输出,便于调试

安全提升:
- DIFY_API_KEY 从前端移至后端,不再暴露在客户端代码
- 使用统一的 JWT 认证体系,提高系统安全性

文档:
- 新增 dify-proxy-backend-integration.md - 后端对接文档(包含完整 FastAPI 实现示例)
- 新增 dify-frontend-modification-summary.md - 前端修改总结
- 新增 CLAUDE.md - 项目架构说明文档

影响范围:
- app/services/dify-client.server.ts - 核心服务层
- app/routes/api.chat-messages.tsx - 聊天消息
- app/routes/api.parameters.tsx - 应用参数
- app/routes/api.conversations.tsx - 会话列表
- app/routes/api.messages.tsx - 消息历史
- app/routes/api.conversations.$id.tsx - 删除会话
- app/routes/api.conversations.$id.name.tsx - 重命名会话

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-30 09:47:48 +08:00
parent 064f05ffa5
commit c4c08cb59b
11 changed files with 2036 additions and 60 deletions
+300
View File
@@ -0,0 +1,300 @@
# Dify 客户端 JWT 认证改造 - 前端修改总结
## 📅 修改信息
- **修改日期**: 2025-01-XX
- **版本**: v2.0 - JWT 认证版本
- **修改类型**: 架构升级 - 从直连改为代理模式
---
## 🎯 修改目标
将 Dify AI 服务调用从 **前端直连** 改为 **通过 FastAPI 后端代理**,并使用 **JWT 认证**替代原有的 API KEY。
---
## 📋 核心变更
### **架构变更**
```
旧: 前端 → Dify API (使用 API_KEY)
新: 前端 → FastAPI 后端 (使用 JWT) → Dify API (使用 API_KEY)
```
### **认证方式变更**
```
旧: Authorization: Bearer {DIFY_API_KEY}
新: Authorization: Bearer {frontendJWT}
```
### **API 端点变更**
```
旧: https://api.dify.ai/v1/chat-messages
新: http://172.16.0.55:8000/dify/chat-messages
```
---
## 📁 修改的文件清单
### **1. 核心服务层** (1 个文件)
-`app/services/dify-client.server.ts` - Dify 客户端核心
**主要修改**
- 导入 `API_BASE_URL` 从配置文件
- `DIFY_CONFIG.API_URL` 改为 `${API_BASE_URL}/dify`
- `difyFetch` 函数添加 `jwt` 参数
- 所有 client 方法添加 `jwt?` 参数
- 添加 401 错误处理(JWT 认证失败)
### **2. API 路由层** (6 个文件)
所有路由都添加了 JWT 获取、验证和传递逻辑:
-`app/routes/api.chat-messages.tsx` - 聊天消息发送
-`app/routes/api.parameters.tsx` - 应用参数获取
-`app/routes/api.conversations.tsx` - 会话列表获取
-`app/routes/api.messages.tsx` - 会话消息历史
-`app/routes/api.conversations.$id.tsx` - 会话删除
-`app/routes/api.conversations.$id.name.tsx` - 会话重命名
**统一修改模式**
```typescript
// 1. 获取 JWT
const { getUserSession } = await import("~/api/login/auth.server");
const { frontendJWT } = await getUserSession(request);
// 2. JWT 验证
if (!frontendJWT) {
return json({ error: 'JWT认证失败,请重新登录' }, { status: 401 });
}
// 3. 传递给 difyClient
await difyClient.method(..., frontendJWT);
// 4. 错误处理
const status = error.message?.includes('JWT认证失败') ? 401 : 500;
```
---
## 🔐 配置迁移说明
### **前端配置(已废弃)**
```bash
# .env - 这些配置不再使用
NEXT_PUBLIC_APP_ID=http://nas.7bm.co:12980/app/46539478-3281-4e98-a445-6da9dc078e95/configuration
NEXT_PUBLIC_APP_KEY=app-N3su9tKyMMnqxt2EMgOkVof7
```
### **后端配置(需要添加)**
**这些配置应该移到 FastAPI 后端**:
```python
# FastAPI 环境变量配置
DIFY_API_URL = "http://nas.7bm.co:12980/v1"
DIFY_API_KEY = "app-N3su9tKyMMnqxt2EMgOkVof7"
DIFY_APP_ID = "46539478-3281-4e98-a445-6da9dc078e95"
```
### **前端新配置**
```bash
# .env - 前端只需要配置 FastAPI 地址
API_BASE_URL=http://172.16.0.55:8000
```
---
## 🛣️ 后端需要实现的路由
| 路由 | 方法 | 说明 |
|------|------|------|
| `/dify/parameters` | GET | 获取应用参数 |
| `/dify/conversations` | GET | 获取会话列表 |
| `/dify/messages` | GET | 获取会话消息历史 |
| `/dify/chat-messages` | POST | 发送聊天消息(支持流式) |
| `/dify/conversations/{id}/name` | POST | 重命名会话 |
| `/dify/conversations/{id}` | DELETE | 删除会话 |
| `/dify/messages/{id}/feedbacks` | POST | 消息反馈 |
**详细对接文档**: `docs/dify-proxy-backend-integration.md`
---
## ⚠️ 关键注意事项
### **1. JWT 认证必须实现**
- 所有请求都携带 `Authorization: Bearer {JWT}`
- JWT 验证失败必须返回 **401 状态码**
- 错误格式:`{"error": "JWT认证失败,请重新登录"}`
### **2. 流式响应必须支持**
- `/dify/chat-messages` 接口支持流式响应(SSE
- 响应头:`Content-Type: text/event-stream`
- 不能缓冲,必须实时转发
### **3. 配置安全**
- `DIFY_API_KEY` 只能存在后端
- 前端代码中不再包含任何 Dify 凭据
- 所有敏感配置通过环境变量管理
### **4. 错误处理**
- JWT 不存在: **401**
- JWT 过期/无效: **401**
- 其他错误: **500**
---
## 🧪 测试清单
### **前端测试**
- [ ] 聊天消息发送(流式)
- [ ] 聊天消息发送(非流式)
- [ ] 会话列表加载
- [ ] 会话切换和消息历史
- [ ] 会话重命名
- [ ] 会话删除
- [ ] JWT 过期后跳转登录
### **后端测试**
- [ ] JWT 验证逻辑
- [ ] 所有 API 路由返回正确
- [ ] 流式响应正常工作
- [ ] 错误返回正确状态码
- [ ] 日志记录完整
---
## 📊 代码统计
- **修改文件数**: 7 个
- **新增代码行数**: ~150 行
- **修改代码行数**: ~200 行
- **核心逻辑变更**: 认证方式 + API 端点
---
## 🚀 部署步骤
### **1. 后端准备**
```bash
# 1. 在 FastAPI 中实现 /dify/* 路由
# 2. 配置 Dify API 凭据
# 3. 集成 JWT 验证逻辑
# 4. 测试所有接口
```
### **2. 前端部署**
```bash
# 1. 确认后端已就绪
npm run build
npm run start
```
### **3. 联调测试**
```bash
# 1. 测试聊天功能
# 2. 测试会话管理
# 3. 测试 JWT 过期处理
# 4. 检查日志输出
```
---
## 📝 代码示例
### **前端调用示例**
```typescript
// app/routes/api.chat-messages.tsx
const { getUserSession } = await import("~/api/login/auth.server");
const { frontendJWT } = await getUserSession(request);
const response = await difyClient.createChatMessage(
inputs,
query,
user,
responseMode,
conversationId,
files,
frontendJWT // 传递 JWT
);
```
### **后端实现示例**
```python
# FastAPI 路由
@app.post("/dify/chat-messages")
async def create_chat_message(
request: Request,
authorization: str = Header(None)
):
# 1. 验证 JWT
jwt_token = authorization.replace("Bearer ", "")
user_info = verify_jwt(jwt_token)
if not user_info:
raise HTTPException(status_code=401, detail="JWT认证失败")
# 2. 调用 Dify API
headers = {"Authorization": f"Bearer {DIFY_API_KEY}"}
body = await request.json()
# 3. 转发流式响应
if body.get("response_mode") == "streaming":
return StreamingResponse(...)
```
---
## 📞 支持与文档
### **详细文档**
- **后端对接文档**: `docs/dify-proxy-backend-integration.md`
- **JWT 实现文档**: `docs/JWT_IMPLEMENTATION.md`
- **CLAUDE.md**: 项目总体架构说明
### **相关链接**
- [Dify 官方文档](https://docs.dify.ai/)
- [FastAPI 文档](https://fastapi.tiangolo.com/)
- [JWT 规范](https://jwt.io/)
---
## ✅ 检查清单
### **前端(已完成)**
- [x] dify-client.server.ts 修改
- [x] 所有 API 路由添加 JWT
- [x] 错误处理完善
- [x] 日志输出优化
- [x] 配置迁移说明
### **后端(待实现)**
- [ ] /dify/* 路由实现
- [ ] JWT 验证集成
- [ ] 流式响应支持
- [ ] 错误处理规范
- [ ] 日志记录完善
- [ ] CORS 配置(如需)
### **联调测试(待完成)**
- [ ] 基础功能测试
- [ ] JWT 认证测试
- [ ] 流式响应测试
- [ ] 错误处理测试
- [ ] 性能测试
---
## 🎉 总结
本次修改完成了 Dify 服务调用的架构升级:
-**安全性提升**: API KEY 不再暴露在前端
-**统一认证**: 使用项目统一的 JWT 认证体系
-**便于管理**: 所有 Dify 配置集中在后端
-**向后兼容**: 保留了原有的 API 接口设计
**下一步**: 等待后端实现完成后进行联调测试。
---
**修改完成日期**: 2025-01-XX
**文档版本**: v1.0