扣子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

Java Web 桂林旅游景点导游平台系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

Java Web 桂林旅游景点导游平台系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

系统架构设计### 摘要 随着信息技术的快速发展,智慧旅游逐渐成为提升旅游体验的重要方向。桂林作为中国著名的旅游城市,拥有丰富的自然景观和人文资源,但传统的旅游信息服务模式存在信息分散、更新滞后、用户体验不佳等问题。游客在规划行程时往往需要从多个平台获取信息,效率较低。因此,开发一个集景点介绍、路线规划、用户评价等功能于一体的智能化导游平台具有重要的现实意义。该平台旨在通过技术手段整合桂林旅游资源,为游客提供一站式服务,提升旅游体验的便捷性和个性化。关键词:智慧旅游、桂林、导游平台、资源整合、用户体验。 本系统采用前后端分离架构,后端基于SpringBoot2框架搭建,结合MyBatis-Plus实现高效的数据操作,数据库选用MySQL8.0以支持高并发访问。前端使用Vue3框架开发,利用其响应式特性提升用户交互体验。系统功能涵盖景点信息展示、用户评论管理、路线推荐、订单管理等模块,并通过JWT实现安全的用户认证。系统设计注重可扩展性和可维护性,采用RESTful API规范进行接口设计,确保前后端高效协作。关键词:SpringBoot2、Vue3、MyBatis-Plus、MyS

Web远程桌面终极指南:3分钟在浏览器中访问任何电脑

还在为复杂的远程控制软件烦恼吗?想要在任何设备上都能轻松访问远程电脑?今天我要向你介绍一个革命性的工具——mstsc.js,这是一个纯JavaScript实现的Microsoft远程桌面协议客户端,让你直接在浏览器中就能实现完整的远程桌面体验! 【免费下载链接】mstsc.jsA pure Node.js Microsoft Remote Desktop Protocol (RDP) Client 项目地址: https://gitcode.com/gh_mirrors/ms/mstsc.js 快速启动:三步搭建你的个人远程控制中心 搭建属于自己的Web远程桌面服务异常简单,只需要三个基础步骤: 第一步:获取项目源码 git clone https://gitcode.com/gh_mirrors/ms/mstsc.js cd mstsc.js 第二步:安装必要组件 npm

XSS 攻击深度解析:前端安全的核心威胁与实战防御指南

XSS 攻击深度解析:前端安全的核心威胁与实战防御指南

XSS 攻击深度解析:前端安全的核心威胁与实战防御指南 在 Web 安全领域,XSS(Cross-Site Scripting,跨站脚本攻击)一直是排名第一的高危漏洞类型。无论是大型互联网公司,还是中小企业网站,都深受其害。XSS 攻击不仅能窃取用户 Cookie、伪造身份,还能篡改页面内容、传播恶意代码,甚至引发大规模用户数据泄露。 本文将从 XSS 的本质原理出发,深入讲解三大类型 XSS 的攻击方式、触发条件、绕过技巧,并给出企业可落地的防御方案,帮助前端开发者与安全工程师建立完整的 XSS 攻防体系。 一、XSS 攻击的本质:把恶意脚本注入到别人的页面里 XSS 攻击的核心原理是: 攻击者通过各种方式,将恶意 JavaScript 代码注入到目标网站的页面中,当用户访问该页面时,恶意代码在用户浏览器中执行,从而实现攻击目的。 一句话总结: XSS = 注入 + 执行

【前端小站】HTML 标签:网页骨架,从空白到惊艳,全靠这些 HTML 标签搞事情

【前端小站】HTML 标签:网页骨架,从空白到惊艳,全靠这些 HTML 标签搞事情 HTML 标签就像积木,不同的组合方式决定了你能搭出什么样的房子。 下面这张图是目前(2025–2026)最常用、最有语义价值、实际项目中出现频率最高的标签分类速览表: 层级主要职责核心标签(按重要性排序)2025–2026 高频使用场景语义分值(SEO/无障碍)文档根声明 + 语言 + 根元素<!DOCTYPE html><html lang="zh-CN">几乎所有页面★★★★★元信息不显示但极其重要<meta charset="UTF-8"><meta name=