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>
7.2 KiB
7.2 KiB
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}/difydifyFetch函数添加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- 会话重命名
统一修改模式:
// 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;
🔐 配置迁移说明
前端配置(已废弃)
# .env - 这些配置不再使用
NEXT_PUBLIC_APP_ID=http://nas.7bm.co:12980/app/46539478-3281-4e98-a445-6da9dc078e95/configuration
NEXT_PUBLIC_APP_KEY=app-N3su9tKyMMnqxt2EMgOkVof7
后端配置(需要添加)
这些配置应该移到 FastAPI 后端:
# FastAPI 环境变量配置
DIFY_API_URL = "http://nas.7bm.co:12980/v1"
DIFY_API_KEY = "app-N3su9tKyMMnqxt2EMgOkVof7"
DIFY_APP_ID = "46539478-3281-4e98-a445-6da9dc078e95"
前端新配置
# .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. 后端准备
# 1. 在 FastAPI 中实现 /dify/* 路由
# 2. 配置 Dify API 凭据
# 3. 集成 JWT 验证逻辑
# 4. 测试所有接口
2. 前端部署
# 1. 确认后端已就绪
npm run build
npm run start
3. 联调测试
# 1. 测试聊天功能
# 2. 测试会话管理
# 3. 测试 JWT 过期处理
# 4. 检查日志输出
📝 代码示例
前端调用示例
// 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
);
后端实现示例
# 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-client.server.ts 修改
- 所有 API 路由添加 JWT
- 错误处理完善
- 日志输出优化
- 配置迁移说明
后端(待实现)
- /dify/* 路由实现
- JWT 验证集成
- 流式响应支持
- 错误处理规范
- 日志记录完善
- CORS 配置(如需)
联调测试(待完成)
- 基础功能测试
- JWT 认证测试
- 流式响应测试
- 错误处理测试
- 性能测试
🎉 总结
本次修改完成了 Dify 服务调用的架构升级:
- ✅ 安全性提升: API KEY 不再暴露在前端
- ✅ 统一认证: 使用项目统一的 JWT 认证体系
- ✅ 便于管理: 所有 Dify 配置集中在后端
- ✅ 向后兼容: 保留了原有的 API 接口设计
下一步: 等待后端实现完成后进行联调测试。
修改完成日期: 2025-01-XX 文档版本: v1.0