c4c08cb59b
主要变更: - 修改 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>
301 lines
7.2 KiB
Markdown
301 lines
7.2 KiB
Markdown
# 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
|