扣子Coze实现ChatSDK的会话隔离(纯前端,萌新必看)

项目背景

使用coze提供的代码在网页插入智能体后,发现不同用户之间没有实现会话隔离(可以互相看到对话记录)。

虽然官方文档里也给了解决方案 ,但写的很粗略,对低代码用户非常不友好,而且示例代码给的还是python的,岂不是说要再部署个后端才能实现。

本文提供一个前端实现用户隔离的方案。

实现原理

先来看官方提供的代码:

<script src="https://lf-cdn.coze.cn/obj/unpkg/flow-platform/chat-app-sdk/1.2.0-beta.10/libs/cn/index.js"></script> <script> new CozeWebSDK.WebChatClient({ //创建一个智能体界面 config: { bot_id: '**********', // 智能体ID }, componentProps: { title: 'Coze', }, auth: { type: 'token', token: 'pat_********', // 访问令牌 onRefreshToken: function () { return 'pat_********' // 备用访问令牌,可以不填 } } }); </script>

由于coze是根据令牌来区分对话记录,而我们又把令牌写死在代码里,导致所有用户使用的是同一个令牌,看到的就是相同的对话记录。

也就是说,只要给不同用户发不同的令牌,就可以实现用户隔离了。

我们可以使用coze提供的OAuth应用来为每个用户自动申请新令牌,完整流程见下图。

流程对比

前期准备

需要准备以下四个东西:

  • 智能体 ID
  • OAuth ID
  • OAuth 公钥
  • OAuth 私钥

智能体

创建并发布智能体,智能体ID可以在地址栏里找到。

点开智能体,ID在地址栏里

OAuth

创建OAuth应用,类型为服务类应用,保存应用ID。

创建OAuth应用,类型为服务类应用

权限勾选 "Bot管理"、"会话管理"、"文件"、"消息"

设置权限

点击创建Key,保存生成的公钥和私钥,私钥文件用记事本打开即可

创建密钥

完整代码

js代码:

// 加载JWT生成库并初始化Coze智能体,替换你的配置后,加到网页的js里 (function() { // 配置参数(替换为你的实际信息) const COZE_CONFIG = { botId: '1145141145141', //智能体 ID appId: '*************',//OAuth ID publicKey: '******************************************************', //OAuth 公钥 privateKey:`-----BEGIN PRIVATE KEY----- ****************************************************** ****************************************************** -----END PRIVATE KEY-----` //OAuth 私钥,全复制进来 }; // 加载JWT库 function loadJwtLibrary() { return new Promise((resolve, reject) => { // 检查是否加载成功 if (window.KJUR && window.KJUR.jws && window.KJUR.jws.JWS) { resolve(); return; } const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/8.0.20/jsrsasign-all-min.js'; script.type = 'text/javascript'; script.crossOrigin = 'anonymous'; // 处理跨域问题 // 加载成功回调 script.onload = () => { // 验证库是否正确加载 if (window.KJUR && window.KJUR.jws && window.KJUR.jws.JWS) { resolve(); } else { reject(new Error('JWT库加载但未正确初始化')); } }; // 加载失败回调 script.onerror = () => { reject(new Error(`JWT库加载失败,请检查链接: ${script.src}`)); }; document.head.appendChild(script); }); } // 生成符合Coze要求的JWT function generateCozeJwt(userUid) { const header = { alg: 'RS256', typ: 'JWT', kid: COZE_CONFIG.publicKey }; const currentTime = Math.floor(Date.now() / 1000); const payload = { iss: COZE_CONFIG.appId, aud: "api.coze.cn", jti: Math.random().toString(36).substr(2, 32) + Date.now(), iat: currentTime, exp: currentTime + 3600, session_name: userUid }; const formattedPublicKey = COZE_CONFIG.privateKey; return window.KJUR.jws.JWS.sign( header.alg, JSON.stringify(header), JSON.stringify(payload), formattedPublicKey ); } // 获得Token并创建Coze智能体界面 async function getAccessToken(jwt) { try { const response = await fetch("https://api.coze.cn/api/permission/oauth2/token", { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${jwt}` }, body: JSON.stringify({ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', duration_seconds: 900 }) }); if (!response.ok) { throw new Error(`获取token失败,HTTP状态码: ${response.status}`); } const data = await response.json(); new CozeWebSDK.WebChatClient({ config: { bot_id: COZE_CONFIG.botId }, componentProps: { title: 'Coze AI助手' }, auth: { type: 'token', token: data.access_token, onRefreshToken: () => data.access_token } }); } catch (error) { throw new Error(`获取Access Token失败: ${error.message}`); } } // 获取用户唯一标识 function getUserUid() { // 从本地存储获取登录用户ID const loggedUserId = localStorage.getItem('website_user_id'); if (loggedUserId) return loggedUserId; // 生成临时访客ID let visitorId = localStorage.getItem('coze_visitor_id'); if (!visitorId) { visitorId = `visitor_${Date.now()}_${Math.random().toString(36).slice(-6)}`; localStorage.setItem('coze_visitor_id', visitorId); } return visitorId; } // 初始化Coze聊天 function initCozeChat() { if (!window.CozeWebSDK || !window.CozeWebSDK.WebChatClient) { console.error('Coze SDK未加载'); return; } const userUid = getUserUid(); const jwtToken = generateCozeJwt(userUid); getAccessToken(jwtToken); } // 加载Coze SDK function loadCozeSdk() { const script = document.createElement('script'); script.src = "https://lf-cdn.coze.cn/obj/unpkg/flow-platform/chat-app-sdk/1.2.0-beta.10/libs/cn/index.js"; script.onload = initCozeChat; script.onerror = () => console.error(`Coze SDK加载失败: ${COZE_CONFIG.sdkSrc}`); document.head.appendChild(script); } // 初始化流程 async function init() { try { await loadJwtLibrary(); loadCozeSdk(); } catch (error) { console.error('初始化失败:', error.message); } } // 页面加载完成后初始化 if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } })();

把测试网页也贴一下,创建一个txt文件,把代码复制进去,再重命名为index.html,双击打开就可以了。

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Coze 智能体测试页面</title> </head> <body> <div> <div> <h1>Coze 智能体测试页面</h1> </div> </div> <script> //在此插入上述代码 </script> </body> </html>

成功的话应该会看到这样的界面,并且实现了用户对话隔离:

成功加载

安全问题

由于直接把公钥和私钥写在了js里,肯定有安全问题,但毕竟是全靠前端实现,不知道有啥解决方案( •̀ ω •́ )✧。

Read more

GLM-4.6V-Flash-WEB Web界面使用指南,拖图就出结果

GLM-4.6V-Flash-WEB Web界面使用指南,拖图就出结果 你不需要配置环境、不用写一行推理代码、甚至不用打开终端——只要把一张截图拖进浏览器窗口,几秒钟后,它就能告诉你图里写了什么、画了什么、哪里有问题。这不是未来预告,而是你现在就能在本地跑起来的真实体验。 GLM-4.6V-Flash-WEB 是智谱AI最新开源的轻量级视觉语言模型,专为Web端实时交互而生。它不像某些“实验室模型”那样只存在于论文和Benchmark表格里,而是真正做到了:部署快、启动快、响应快、上手更快。一块RTX 3090,一个浏览器,一次拖拽,结果即刻呈现。 本文不讲训练原理,不列参数表格,不堆技术术语。我们只聚焦一件事:怎么用好它的Web界面?从零开始,到稳定产出,每一步都清晰可操作。 1. 为什么说“拖图就出结果”不是宣传话术? 很多多模态模型标榜“支持图文理解”,但实际用起来才发现:要装依赖、改路径、调精度、修CUDA版本、

前端防范 XSS(跨站脚本攻击)

目录 一、防范措施 1.layui util  核心转义的特殊字符 示例 2.js-xss.js库 安装 1. Node.js 环境(npm/yarn) 2. 浏览器环境 核心 API 基础使用 1. 基础过滤(默认规则) 2. 自定义过滤规则 (1)允许特定标签 (2)允许特定属性 (3)自定义标签处理 (4)自定义属性处理 (5)转义特定字符 常见场景示例 1. 过滤用户输入的评论内容 2. 允许特定富文本标签(如富文本编辑器内容) 注意事项 更多配置 XSS(跨站脚本攻击)是一种常见的网络攻击手段,它允许攻击者将恶意脚本注入到其他用户的浏览器中。

详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)

详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)

目录 1. 打开浏览器开发者工具 2. 使用 Network 面板 3. 查看具体的API请求 a. Headers b. Payload c. Response d. Preview e. Timing 4. 实际操作步骤 5. 常见问题及解决方法 a. 无法看到API请求 b. 请求失败 c. 跨域问题(CORS) 作为一名后端工程师,理解前端如何调用接口、传递参数以及接收返回值是非常重要的。下面将详细介绍如何通过浏览器开发者工具(F12)查看和分析这些信息,并附带图片案例帮助你更好地理解。 1. 打开浏览器开发者工具 按下 F12 或右键点击页面选择“检查”可以打开浏览器的开发者工具。常用的浏览器如Chrome、Firefox等都内置了开发者工具。下面是我选择我的一篇文章,打开开发者工具进行演示。 2. 使用

Cursor+Codex隐藏技巧:用截图秒修前端Bug的保姆级教程(React/Chakra UI案例)

Cursor+Codex隐藏技巧:用截图秒修前端Bug的保姆级教程(React/Chakra UI案例) 前端开发中最令人头疼的莫过于那些难以定位的UI问题——元素错位、样式冲突、响应式失效...传统调试方式往往需要反复修改代码、刷新页面、检查元素。现在,通过Cursor编辑器集成的Codex功能,你可以直接用截图交互快速定位和修复这些问题。本文将带你从零开始,掌握这套革命性的调试工作流。 1. 环境准备与基础配置 在开始之前,确保你已经具备以下环境: * Cursor编辑器最新版(v2.5+) * Node.js 18.x及以上版本 * React 18项目(本文以Chakra UI 2.x为例) 首先在Cursor中安装Codex插件: 1. 点击左侧扩展图标 2. 搜索"Codex"并安装 3. 登录你的OpenAI账户(需要ChatGPT Plus订阅) 关键配置项: // 在项目根目录创建.