跳到正文
AskTable

文档反馈

当前页面用户身份嵌入/integrations/user-embed

0 / 5,000

反馈将发送给维护团队。

前往控制台
前往控制台

接入与开发

用用户身份嵌入对话和工作区

以当前用户的 AskTable 身份,把对话或项目工作区嵌入你的网站。

用户身份嵌入把 AskTable 页面放进你的网站,并使用当前用户自己的 AskTable 身份:组织、项目和数据权限都与他直接登录 AskTable 时相同。适合内部平台和企业门户。

访客不需要登录、所有人共用一个数据范围时,改用匿名嵌入。

入口说明:项目侧栏 →「Agent 集成」→「在业务系统中集成 AskTable」→「iframe」。

选择方式

方式适合页面范围
Chat在已有业务页面中加入对话,由你的网站管理对话列表当前用户本人的一段对话
Workspace把 AskTable 工作区放进内部平台或门户指定组织内的项目工作区,可以切换项目

两种方式都需要当前用户的 AskTable 用户凭证(user_token)。你的平台要先通过已有的登录或单点登录流程换取该用户的 AskTable 凭证。不能用 API Key 或共享的管理员凭证代表所有用户。

Chat

  1. 准备 AskTable 网站地址、组织 ID、项目 ID、智能体 ID 和当前用户的凭证。

  2. 调用接口列出本人的对话,或指定智能体创建一段对话,取得对话 id:

    GET /api/v1/conversations?created_by_me=true&types=chat&page=1&size=20&sort=modified_desc
    Authorization: Bearer <当前用户的 AskTable 凭证>
    X-Project-Id: <项目 ID>
    POST /api/v1/conversations
    Authorization: Bearer <当前用户的 AskTable 凭证>
    X-Project-Id: <项目 ID>
    Content-Type: application/json
    
    {"type":"chat","data_agent_id":"<智能体 ID>"}

    示例使用一体化部署的 /api 前缀,Cloud 和其他部署按实际 API 地址替换。

  3. 用对话 ID 构造地址,按下文的握手协议传入凭证:

    <网站地址>/user-embed/p/<项目 ID>/conv/<对话 ID>?org_id=<组织 ID>&parent_origin=<编码后的父页面来源>

创建对话不会自动发送问题。切换对话时更新 iframe 地址并重新握手。此入口只能打开本人的对话,管理员也不能借此查看他人的对话。

Workspace

<网站地址>/workspace-embed?org_id=<组织 ID>&parent_origin=<编码后的父页面来源>&project_id=<初始项目 ID>
  • project_id 可选,不传时显示用户可访问的项目列表。
  • 用户按现有权限使用对话、智能体、数据源、技能、项目设置等功能,可以在组织内切换项目;不提供组织切换和系统管理入口。
  • 在地址的 # 之前加上 &layout=content,会隐藏 AskTable 的项目侧栏和移动端菜单按钮,适合由你的网站菜单直接打开某个项目页面,例如 ...&layout=content#/u/p/<项目 ID>/data/data-source。私有部署需 4.2.76 及以上。

握手协议

两种方式都必须传 org_id 和 parent_origin。parent_origin 取父页面的 location.origin(协议、主机和非默认端口,不带路径和末尾斜杠),用 URLSearchParams 编码。

先注册消息监听,再设置 iframe 地址。 以下是 Workspace 的示例;Chat 使用 Chat 地址,把 mode 换成 chat,并同时核对消息中的项目 ID 和对话 ID。

<iframe id="asktable" title="AskTable" style="width:100%;height:700px;border:0"></iframe>
const webBase = 'https://asktable.example.com'; // 可以包含部署子路径,不带末尾斜杠
const askTableOrigin = new URL(webBase).origin;
const orgId = '你的组织 ID';
const projectId = '你的项目 ID';
const frame = document.getElementById('asktable');
let channelId;
let generation = 0;
let closing = false;

window.addEventListener('message', async (event) => {
  if (event.origin !== askTableOrigin || event.source !== frame.contentWindow) return;
  const m = event.data;
  if (!m || m.mode !== 'workspace' || m.org_id !== orgId) return;
  if (m.type === 'asktable.ready' && !closing) {
    channelId = m.channel_id;
    const current = ++generation;
    try {
      // 由你的应用实现:取得当前用户的 AskTable 用户凭证。
      const token = await getCurrentAskTableUserToken();
      if (closing || current !== generation) return;
      frame.contentWindow.postMessage({
        type: 'asktable.authenticate', channel_id: channelId, token
      }, askTableOrigin);
    } catch (error) {
      if (!closing && current === generation) showIntegrationError(error);
    }
    return;
  }
  if (!channelId || m.channel_id !== channelId) return;
  if (m.type === 'asktable.loaded') hideLoading();
  if (m.type === 'asktable.error') showIntegrationError(m.code);
  if (m.type === 'asktable.auth_required') {
    // 交回登录入口;登录成功后重新加载 iframe,限制重试次数。
    ++generation;
    showSignIn();
  }
  if (m.type === 'asktable.logged_out') {
    ++generation;
    closing = true;
    frame.src = 'about:blank'; // 收到退出确认后才卸载。
  }
});

const params = new URLSearchParams({
  org_id: orgId, parent_origin: location.origin, project_id: projectId
});
frame.src = `${webBase}/workspace-embed?${params}`;

function logoutAskTable() {
  closing = true;
  ++generation; // 丢弃尚未完成的凭证请求。
  if (channelId) frame.contentWindow.postMessage({
    type: 'asktable.logout', channel_id: channelId
  }, askTableOrigin);
}

getCurrentAskTableUserToken、hideLoading、showIntegrationError、showSignIn 由你的应用实现。正式接入时,还应为加载、取凭证和退出设置超时提示;重新加载、换账号或切换对话前,让旧的凭证请求失效。多个 iframe 分别维护各自的握手状态。

消息方向含义与处理
asktable.readyiframe → 父页面记录新的 channel_id,发送 authenticate
asktable.authenticate父页面 → iframe携带当前 channel 和用户凭证;目标来源必须精确匹配,不能用 *
asktable.authenticatediframe → 父页面身份确认成功,不代表有权访问目标页面
asktable.loadediframe → 父页面目标页面的必要数据已就绪,可以移除加载遮罩
asktable.auth_requirediframe → 父页面取得新凭证后重新认证;限制重试次数,失败后让用户重新登录
asktable.erroriframe → 父页面显示错误或重试入口;权限错误不能靠刷新凭证解决
asktable.logout父页面 → iframe请求退出,携带当前 channel_id
asktable.logged_outiframe → 父页面已清除凭证,此后才能销毁 iframe;用户在 iframe 内主动退出时也会发送

AskTable 发出的消息都带 mode、org_id 和 channel_id;Chat 还带 project_id、conversation_id。父页面必须核对这些字段、消息来源和发送窗口,只处理当前 channel 的消息。同一用户续期凭证时可能只再次收到 authenticated,输入框中的草稿会保留。

登录与退出

  • 验证身份后,凭证保存在 AskTable 自己域名的浏览器存储中。同一浏览器里,iframe 和直接打开的 AskTable 页面共用同一个身份:换账号会覆盖原账号,退出会同时退出两边。不能用来让多个账号并行使用。
  • 关闭 iframe 不等于退出。先发送 logout,收到 logged_out 后再卸载。退出只清除浏览器中的凭证,不会撤销服务端的凭证。
  • 凭证不要放进 URL、不要写入日志,也不要保存到你网站的 localStorage。
  • 部分浏览器会限制第三方存储,请在实际域名和目标浏览器中验证登录、刷新、续期、换账号和退出。

部署检查

  • AskTable Web 容器的 EMBED_ORIGINS 默认为 *,允许所有 HTTP/HTTPS 父页面。需要限制时改为逗号分隔的精确来源列表;设为空字符串表示禁止握手。放行来源不授予任何用户权限。
  • 反向代理或 CDN 要允许 /workspace-embed 和 /user-embed/ 被嵌入,检查 X-Frame-Options 和 CSP frame-ancestors;你的网站的 CSP frame-src 也要允许 AskTable。
  • HTTPS 页面不能嵌入 HTTP 页面。如果给 iframe 设置了 sandbox,至少需要 allow-scripts allow-same-origin,下载按需放行。
  • 只通过 postMessage 传凭证时,不需要为你的网站开放 API 跨域。你的网站直接调用 AskTable API 时,另行配置跨域。代理流式回复时需关闭缓冲并允许长连接。

从旧版 Chat 嵌入升级

在 4.2.66 之前接入 Chat 嵌入的平台,升级到 4.2.66 及以上后需要:在地址中补充 org_id;在消息校验中加入 mode=chat 和 org_id;退出时等待 logged_out 再关闭窗口。AskTable 前端和服务端需要同时升级。

验收

在实际域名中验证:无权限的访问会被拒绝;只能打开本人的对话;能切换项目;上传、下载和流式回复正常;登录、刷新、续期、换账号和退出都符合预期。