Skip to content

fix(share): stabilize revoke API and error diagnostics#39

Merged
mosshello merged 13 commits intomasterfrom
feature/share-link-embed
Apr 3, 2026
Merged

fix(share): stabilize revoke API and error diagnostics#39
mosshello merged 13 commits intomasterfrom
feature/share-link-embed

Conversation

@zjhong
Copy link
Copy Markdown
Contributor

@zjhong zjhong commented Apr 3, 2026

🚀 新功能:分享链接 - 无状态仪表板嵌入

概述

实现了无状态的分享链接功能,允许通过 UUID v4 令牌嵌入 ThingsVis 仪表板,无需复杂的 SSO Token 交换流程。

主要变更

后端 API

数据库 Schema

  • 添加 shareToken (UUID v4), shareExpiry, shareEnabled 字段到 Dashboard 模型
  • 数据库迁移已应用

API 端点

  • POST /api/v1/dashboards/:id/share - 创建分享链接(需认证)
  • GET /api/v1/dashboards/:id/share - 查询分享信息,Token 脱敏(需认证)
  • DELETE /api/v1/dashboards/:id/share - 吊销分享链接(需认证)
  • GET /api/v1/dashboards/:id/validate-share - 验证分享链接(无需认证

前端实现

API 客户端

  • 扩展 apiClient 支持 skipAuth 选项
  • 添加 createShareLink, validateShareLink, revokeShareLink, getShareInfo 函数

EmbedPage 支持

  • 支持 shareToken URL 参数
  • URL 参数优先级:shareToken > token
  • 完全向后兼容现有 SSO Token 流程

UI 组件

  • ShareDashboardDialog - 完整的分享管理对话框
  • 支持设置过期时间(1/7/30 天或永久)
  • 一键复制分享链接
  • 实时显示过期状态

文档

集成指南

  • 完整的 API 文档
  • 前端集成示例
  • ThingsPanel 集成指南
  • 安全最佳实践
  • 迁移指南

功能特性

🔒 安全性

  • UUID v4 生成 shareToken(128-bit 随机)
  • 支持过期时间设置
  • 支持实时吊销
  • 查询接口返回脱敏 Token

�� 向后兼容

  • 保留现有 SSO Token 机制
  • 不影响现有嵌入流程
  • 可以与 SSO Token 共存

⚡ 无状态设计

  • 完全无状态验证
  • 无需维护会话
  • 简化嵌入流程

📊 使用简单

// 创建分享链接
const result = await createShareLink('dash_123', { expiresIn: 86400 });

// 嵌入
<iframe src={result.data.shareUrl} />

测试

✅ 构建测试通过

  • Server 构建成功
  • Studio 构建成功
  • 所有 lint 检查通过

⏸️ 待完成(可选)

  • API 端到端测试
  • 前端集成测试

文件变更

核心文件

  • apps/server/prisma/schema.prisma - 数据模型
  • apps/server/src/app/api/v1/dashboards/[id]/share/route.ts - 分享 CRUD
  • apps/server/src/app/api/v1/dashboards/[id]/validate-share/route.ts - 验证 API
  • apps/studio/src/lib/api/client.ts - API 客户端增强
  • apps/studio/src/lib/api/dashboards.ts - 分享 API 封装
  • apps/studio/src/pages/EmbedPage.tsx - shareToken 支持
  • apps/studio/src/components/dashboard/ShareDashboardDialog.tsx - UI 组件

文档

  • docs/integration/share-link-integration.md - 集成指南
  • FEATURE_SUMMARY.md - 功能总结

部署注意事项

  1. 数据库迁移:部署前需要运行数据库迁移
  2. 向后兼容:不影响现有功能,可以安全部署
  3. HTTPS:生产环境建议使用 HTTPS

相关文档

Checklist

  • 代码实现完成
  • 构建测试通过
  • 文档完善
  • 向后兼容
  • API 测试(可选)
  • 集成测试(可选)

预览

创建分享链接并嵌入:

<iframe 
  src="https://thingsvis.example.com/#/embed?id=dash_123&shareToken=xxx"
  width="100%" 
  height="600">
</iframe>

类型: 新功能
影响范围: 后端 API + 前端 + 数据库
破坏性变更: 无

zjhong and others added 13 commits April 2, 2026 19:49
…e as public endpoint in middleware\n- generate share URLs with frontend AUTH_URL and HashRouter path\n- update testing/integration docs to hash-based embed URLs\n- include manual test helper script\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add Share button to EditorTopNav between Save and Preview
- Import and render ShareDashboardDialog in Editor component
- Only show share button when projectId exists
- Use Share2 icon from lucide-react

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix ShareDashboardDialog props interface: isOpen->open, onClose->onOpenChange
- Add 'share' translation to both zh and en editor i18n files
- Remove i18n fallback value in EditorTopNav
- Ensure share button click handler works correctly

This fixes the issue where clicking share button had no effect.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- surface backend error details when create/revoke share link fails
- show actionable hint when dashboard is not found (save first)
- preserve generated share URL in dialog state after creation
- fully localize share dialog strings (zh/en)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- use same AUTH_SECRET fallback as login/auth helpers
- prevent false Unauthorized in middleware when AUTH_SECRET is unset
- restore bearer token auth for share link create endpoint

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- use localStorage token when in-memory tokenRef is temporarily empty
- prevents intermittent Unauthorized on share link creation
- keeps embed token behavior unchanged

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- fallback to persisted browser token for non-embed requests
- prevent Authorization header from being dropped by runtime token races
- keep embed mode token isolation intact

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Context:
- Unauthorized persisted in normal browser editor while script worked.
- Root cause was treating URL param mode=embedded as true embed context.
- That disabled browser token fallback in non-iframe pages.

Change:
- Determine embed context via window.self !== window.top (safe try/catch).
- Keep token fallback enabled for normal browser pages even if URL contains mode=embedded.
- Preserve isolation for true iframe embed context.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- frontend: collect auth debug events in window.__THINGSVIS_AUTH_DEBUG_LOGS__
- frontend: log token source/request/401 when thingsvis_debug_auth=1
- frontend: log share create failure context under same debug switch
- backend: log header/session diagnostics on share POST when DEBUG_SHARE_AUTH=1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- detect Unauthorized on createShareLink in share dialog
- show clear re-login guidance instead of generic failure
- redirect user to login page for immediate recovery
- add zh/en i18n messages for unauthorized hint

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- avoid json() parse errors on 204/empty responses
- parse response text conditionally before JSON decoding
- fixes revoke share link showing false 'Network error'

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- return 200 JSON for DELETE /share instead of 204 with body\n- add DELETE auth diagnostics on server\n- harden client response parsing for non-JSON payloads\n- include response status/raw text in debug logs\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mosshello mosshello merged commit b6e185d into master Apr 3, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants