diff --git a/app/config/api-config.ts b/app/config/api-config.ts index 255b356..66419aa 100644 --- a/app/config/api-config.ts +++ b/app/config/api-config.ts @@ -72,12 +72,12 @@ const portConfigs: Record> = { // 主要 // 梅州 '51703': { - // baseUrl: 'http://172.16.0.55:8073', - // documentUrl: 'http://172.16.0.55:8073/docauditai/', - // uploadUrl: 'http://172.16.0.55:8073/admin/documents' - baseUrl: 'http://nas.7bm.co:8073', - documentUrl: 'http://nas.7bm.co:8073/docauditai/', - uploadUrl: 'http://nas.7bm.co:8073/admin/documents' + baseUrl: 'http://172.16.0.55:8073', + documentUrl: 'http://172.16.0.55:8073/docauditai/', + uploadUrl: 'http://172.16.0.55:8073/admin/documents' + // baseUrl: 'http://nas.7bm.co:8873', + // documentUrl: 'http://nas.7bm.co:8873/docauditai/', + // uploadUrl: 'http://nas.7bm.co:8873/admin/documents' }, @@ -136,14 +136,11 @@ const configs: Record = { // 测试环境 testing: { - // baseUrl: 'http://172.16.0.55:8873', - // documentUrl: 'http://172.16.0.55:8873/docauditai/', - // uploadUrl: 'http://172.16.0.55:8873/admin/documents', - baseUrl: 'http://nas.7bm.co:8073', - documentUrl: 'http://nas.7bm.co:8073/docauditai/', - uploadUrl: 'http://nas.7bm.co:8073/admin/documents', + baseUrl: 'http://nas.7bm.co:8873', + documentUrl: 'http://nas.7bm.co:8873/docauditai/', + uploadUrl: 'http://nas.7bm.co:8873/admin/documents', oauth: { - serverUrl: 'http://10.79.112.85', // IDaaS服务器地址 + serverUrl: 'http://10.79.112.85', // IDaaS服务器地址 clientId: '54d2a619fe5c81ae1250434c441fccccqMtKwh7H4fO', clientSecret: 'placeholder', // 需要替换为实际的Client Secret redirectUri: 'http://10.79.97.17/', // 回调地址 @@ -162,6 +159,7 @@ const configs: Record = { oauth: { serverUrl: 'http://10.79.112.85', // IDaaS服务器地址 clientId: '54d2a619fe5c81ae1250434c441fccccqMtKwh7H4fO', + // clientSecret: 'VYk1AC5XIJEfnEXwyq0u9JEY3fi3byCfSD58zANGeb', // 需要替换为实际的Client Secret // ⚠️ 安全警告:clientSecret 不应该硬编码在代码中 // 请在生产环境使用环境变量 OAUTH_CLIENT_SECRET clientSecret: 'placeholder', // 占位符,实际值从环境变量获取 diff --git a/docs/URGENT-前端必须修改.md b/docs/URGENT-前端必须修改.md new file mode 100644 index 0000000..5153e3e --- /dev/null +++ b/docs/URGENT-前端必须修改.md @@ -0,0 +1,398 @@ +# 🚨 紧急:前端Dify集成问题修复指南 + +## 问题现状 + +**当前错误**: +```javascript +// ❌ 错误的Authorization头 +Authorization: Bearer app-lHn5EmeACIaLjG9yz0rYIFfM // 这是Dify API Key,不是JWT! + +// ❌ 错误的user字段 +user: "user_34a1d450-6a24-4db7-b1e7-8dd7c0876f14:sess_3z84y7dtuhr" // UUID格式 +``` + +**导致的问题**: +1. 无法加载历史对话记录(user不匹配) +2. 对话没有按用户隔离(所有人共享对话) +3. 安全问题(API Key暴露在前端) + +--- + +## 🎯 必须修改的3个地方 + +### 修改1: Authorization头 - 使用JWT替代Dify API Key + +#### ❌ 旧代码(错误) +```typescript +// app/services/dify-client.server.ts 或类似文件 +const DIFY_API_KEY = "app-lHn5EmeACIaLjG9yz0rYIFfM"; + +async function callDifyAPI(endpoint: string, data: any) { + const response = await fetch(`${DIFY_BASE_URL}${endpoint}`, { + headers: { + 'Authorization': `Bearer ${DIFY_API_KEY}`, // ❌ 错误!暴露API Key + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + return response.json(); +} +``` + +#### ✅ 新代码(正确) +```typescript +// app/services/dify-client.server.ts +// 1. 移除DIFY_API_KEY配置 +// const DIFY_API_KEY = "..."; // 删除这行 + +// 2. 从用户session获取JWT +import { getUserSession } from "~/api/login/auth.server"; + +async function callDifyAPI(request: Request, endpoint: string, data: any) { + // 获取JWT + const { frontendJWT } = await getUserSession(request); + + if (!frontendJWT) { + throw new Error("未登录,请先登录"); + } + + // 使用JWT作为Authorization头 + const response = await fetch(`http://172.16.0.55:8000/dify${endpoint}`, { + headers: { + 'Authorization': `Bearer ${frontendJWT}`, // ✅ 正确!使用JWT + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); + return response.json(); +} +``` + +### 修改2: 请求URL - 指向FastAPI代理而非直连Dify + +#### ❌ 旧代码(错误) +```typescript +// 直连Dify API +const DIFY_BASE_URL = "http://nas.7bm.co:12980/v1"; + +// 示例:获取会话列表 +const response = await fetch( + `${DIFY_BASE_URL}/conversations?user=${user}&limit=100`, + // ... +); +``` + +#### ✅ 新代码(正确) +```typescript +// 通过FastAPI代理访问Dify +const API_BASE_URL = "http://172.16.0.55:8000"; // FastAPI地址 + +// 示例:获取会话列表 +const response = await fetch( + `${API_BASE_URL}/dify/conversations?limit=100`, // ✅ 走/dify代理,不传user + { + headers: { + 'Authorization': `Bearer ${frontendJWT}` // ✅ 使用JWT + } + } +); +``` + +### 修改3: user字段 - 完全移除,让后端自动添加 + +#### ❌ 旧代码(错误) +```typescript +// 生成UUID格式的user +function generateUserId() { + return `user_${crypto.randomUUID()}:sess_${randomString()}`; +} + +// 发送消息 +const data = { + query: "你好", + user: generateUserId(), // ❌ 错误!UUID格式 + conversation_id: null, + response_mode: "streaming", + inputs: {} +}; +``` + +#### ✅ 新代码(正确) +```typescript +// 完全不传user字段,后端会自动添加JWT的username +const data = { + query: "你好", + // user字段完全不传! ✅ 正确 + conversation_id: null, + response_mode: "streaming", + inputs: {} +}; +``` + +--- + +## 📝 完整的修改示例 + +### 示例1: 获取会话列表 + +#### ❌ 旧代码 +```typescript +// app/routes/api.conversations.tsx +export async function loader({ request }: LoaderFunctionArgs) { + const url = new URL(request.url); + const user = url.searchParams.get("user") || generateUserId(); + const limit = url.searchParams.get("limit") || "100"; + + const response = await fetch( + `http://nas.7bm.co:12980/v1/conversations?user=${user}&limit=${limit}`, + { + headers: { + 'Authorization': `Bearer app-lHn5EmeACIaLjG9yz0rYIFfM`, // ❌ Dify API Key + 'Content-Type': 'application/json' + } + } + ); + + return json(await response.json()); +} +``` + +#### ✅ 新代码 +```typescript +// app/routes/api.conversations.tsx +import { getUserSession } from "~/api/login/auth.server"; + +export async function loader({ request }: LoaderFunctionArgs) { + // 1. 获取JWT + const { frontendJWT } = await getUserSession(request); + + if (!frontendJWT) { + return json({ error: "未登录" }, { status: 401 }); + } + + // 2. 调用FastAPI代理(不传user,后端自动添加) + const url = new URL(request.url); + const limit = url.searchParams.get("limit") || "100"; + + const response = await fetch( + `http://172.16.0.55:8000/dify/conversations?limit=${limit}`, // ✅ 走代理 + { + headers: { + 'Authorization': `Bearer ${frontendJWT}`, // ✅ 使用JWT + 'Content-Type': 'application/json' + } + } + ); + + return json(await response.json()); +} +``` + +### 示例2: 发送消息 + +#### ❌ 旧代码 +```typescript +// app/routes/api.chat-messages.tsx +export async function action({ request }: ActionFunctionArgs) { + const body = await request.json(); + + const response = await fetch( + `http://nas.7bm.co:12980/v1/chat-messages`, + { + method: 'POST', + headers: { + 'Authorization': `Bearer app-lHn5EmeACIaLjG9yz0rYIFfM`, // ❌ Dify API Key + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + query: body.query, + user: body.user || generateUserId(), // ❌ UUID格式 + conversation_id: body.conversation_id, + response_mode: "streaming", + inputs: body.inputs || {} + }) + } + ); + + return new Response(response.body, { + headers: { 'Content-Type': 'text/event-stream' } + }); +} +``` + +#### ✅ 新代码 +```typescript +// app/routes/api.chat-messages.tsx +import { getUserSession } from "~/api/login/auth.server"; + +export async function action({ request }: ActionFunctionArgs) { + // 1. 获取JWT + const { frontendJWT } = await getUserSession(request); + + if (!frontendJWT) { + return json({ error: "未登录" }, { status: 401 }); + } + + // 2. 解析请求体 + const body = await request.json(); + + // 3. 调用FastAPI代理(不传user,后端自动添加) + const response = await fetch( + `http://172.16.0.55:8000/dify/chat-messages`, // ✅ 走代理 + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${frontendJWT}`, // ✅ 使用JWT + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + query: body.query, + // user字段完全不传 ✅ 后端自动添加 + conversation_id: body.conversation_id, + response_mode: "streaming", + inputs: body.inputs || {} + }) + } + ); + + return new Response(response.body, { + headers: { 'Content-Type': 'text/event-stream' } + }); +} +``` + +--- + +## 🔍 检查清单 + +### 前端开发者必须检查的文件 + +1. **Dify客户端配置文件** + - 位置:`app/services/dify-client.server.ts` 或类似 + - 检查:是否还有`DIFY_API_KEY`定义?(应该删除) + - 检查:是否还有`DIFY_BASE_URL = "http://nas.7bm.co:12980"`?(应改为FastAPI地址) + +2. **API路由文件** + - 位置:`app/routes/api.*.tsx` 中所有与Dify相关的 + - 检查:所有`fetch`调用是否指向`http://172.16.0.55:8000/dify/*`? + - 检查:所有`Authorization`头是否使用`frontendJWT`? + +3. **user字段生成逻辑** + - 搜索关键字:`generateUserId`, `user_`, `crypto.randomUUID` + - 检查:是否还在生成UUID格式的user?(应该完全移除) + +4. **环境变量配置** + - 位置:`.env` 或 `.env.local` + - 检查:是否还有`DIFY_API_KEY`或`NEXT_PUBLIC_APP_KEY`?(应该删除) + +--- + +## 🧪 验证方法 + +修改完成后,使用浏览器开发者工具验证: + +### 1. 检查Authorization头 +打开 Network 标签,找到Dify相关请求: + +**✅ 正确的请求头**: +``` +Request URL: http://172.16.0.55:8000/dify/conversations?limit=100 +Request Headers: + Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... (JWT格式,很长) + Content-Type: application/json +``` + +**❌ 错误的请求头**: +``` +Request URL: http://nas.7bm.co:12980/v1/conversations?user=xxx +Request Headers: + Authorization: Bearer app-lHn5EmeACIaLjG9yz0rYIFfM (Dify API Key,很短) +``` + +### 2. 检查请求体 +对于POST请求(如发送消息): + +**✅ 正确的请求体**: +```json +{ + "query": "你好", + "conversation_id": null, + "response_mode": "streaming", + "inputs": {} +} +``` +注意:**没有user字段** + +**❌ 错误的请求体**: +```json +{ + "query": "你好", + "user": "user_34a1d450-6a24-4db7-b1e7-8dd7c0876f14:sess_xxx", + "conversation_id": null, + "response_mode": "streaming", + "inputs": {} +} +``` + +### 3. 检查后端日志 +修改后,后端日志应该显示: + +```log +[INFO] Dify请求用户: admin (ID: 5, 路径: conversations) +[INFO] 自动添加user参数: admin +[INFO] 查询参数: {'user': 'admin', 'limit': '100'} +``` + +### 4. 检查Dify后台 +在Dify管理界面的对话列表中,应该看到: +- 新对话的用户显示为:`admin`(或实际的username) +- 不再是:`user_34a1d450...` + +--- + +## ⚠️ 常见错误 + +### 错误1: 前端仍使用DIFY_API_KEY +**症状**:Authorization头是`Bearer app-xxx`(短字符串) +**解决**:删除所有`DIFY_API_KEY`定义,改用`frontendJWT` + +### 错误2: 前端直连Dify +**症状**:请求URL是`http://nas.7bm.co:12980/v1/...` +**解决**:所有URL改为`http://172.16.0.55:8000/dify/...` + +### 错误3: 仍在传递UUID格式的user +**症状**:请求体包含`"user": "user_34a1d450..."` +**解决**:完全删除user字段,不要传递 + +### 错误4: JWT获取失败 +**症状**:`frontendJWT`为`null`或`undefined` +**解决**:检查`getUserSession`导入路径和session配置 + +--- + +## 📋 修改总结 + +| 项目 | 旧值 | 新值 | +|------|------|------| +| Authorization头 | `Bearer app-lHn5EmeACIaLjG9yz0rYIFfM` | `Bearer {frontendJWT}` | +| 请求URL | `http://nas.7bm.co:12980/v1/*` | `http://172.16.0.55:8000/dify/*` | +| user字段 | `user_34a1d450-...` | 完全不传(后端自动添加) | + +--- + +## 🎯 期望结果 + +修改完成后: +- ✅ 每个用户只能看到自己的对话记录 +- ✅ Dify后台显示真实的username(如admin) +- ✅ API Key不再暴露在前端 +- ✅ 所有对话按用户隔离 +- ✅ 历史对话记录正常加载 + +--- + +**紧急程度**: 🔴 高优先级 +**预计修改时间**: 30-60分钟 +**影响范围**: 所有Dify相关功能 + +**联系后端**: 如有疑问,请查看`docs/dify-frontend-user-field-guide.md`获取更多细节 diff --git a/start.sh b/start.sh index 2587088..77306c0 100644 --- a/start.sh +++ b/start.sh @@ -1 +1,3 @@ -npm run start:pm2:multi && tail -f /dev/null \ No newline at end of file +#!/bin/sh +# 启动应用(会先编译再运行) +npm run start:pm2:production:multi && tail -f /dev/null \ No newline at end of file