跳轉到正文
開發者文檔/第三方集成

外部系統嵌入組件

在自有業務系統中通過 iframe 免登錄調用 MuseDAM 素材、文件夾、成員選擇與上傳組件。

最近更新
在業務系統中嵌入組件
01管理員開啟嵌入
02後端用 API Key 簽發 code
03iframe 打開 /outer/embed
04postMessage 調用組件

API Key 只保存在後端;code 5 分鐘內有效且只能使用一次。

適用場景

企業員工已經登錄了你的業務系統(OA、CMS、電商後臺等),需要在其中直接使用 MuseDAM 的素材選擇、文件夾選擇、成員選擇、上傳和標籤選擇組件。

  • 員工打開組件時免登錄,不會跳轉 MuseDAM 登錄頁,也不需要逐個員工授權。
  • 是否開放由團隊管理員統一決定,可隨時開啟、關閉或撤銷。
  • 憑證只能代表本團隊的正常成員,組件內的操作沿用該成員在 MuseDAM 中的權限。

本文適用於「在你的系統中嵌入 MuseDAM 組件」。如果是將你的應用嵌入 MuseDAM 內部運行,請參閱嵌入應用與組件。

接入流程

  1. 團隊管理員為一個團隊 API Key 開啟嵌入組件,並配置允許嵌入的域名。
  2. 員工在你的系統中觸發操作時,你的後端使用該 API Key 調用簽發接口,為該員工獲取一次性 code。
  3. 你的前端用 iframe 打開 https://{MuseDAM 域名}/outer/embed?code=...。
  4. 嵌入頁完成鑑權後,向父頁面發送 musedam-embed-ready 事件。
  5. 前端通過 postMessage 發送 action 打開組件,並按 dispatchId 接收 action_result 結果。
text
你的后端 ──(Bearer 团队 API Key + 员工标识)──► POST /api/muse/embed-code ──► { code, expiresIn }
│
▼ 把 code 交给前端
你的前端 ──► <iframe src="https://musedam.ai/outer/embed?code=...">
◄── musedam-embed-ready
──► action: assets-selector-modal-open
◄── action_result: { success: true, data: { selectedAssets } }

開啟嵌入組件

管理員開啟嵌入

  1. 系統管理員登錄 MuseDAM,進入「團隊設置」→「API 賬號」。
  2. 選擇一個團隊 API Key(如果還沒有,請先按快速開始創建)。
  3. 在 API Key 詳情的「嵌入組件」區域打開開關,填寫允許嵌入的域名並保存。
  4. 開啟後,API Key 列表會顯示「已開啟嵌入」標識。

只有團隊 API Key 能簽發嵌入憑證;個人 API Key、第三方應用憑證均會被拒絕。關閉開關或撤銷 API Key 後,立即無法再簽發新的 code。

配置允許嵌入的域名

「允許嵌入的域名」用於限制哪些父頁面可以加載嵌入頁。配置後,嵌入頁只在父頁面 origin 匹配時進入可用狀態,並且只接收、只發送給該 origin 的消息。

規則說明
格式http(s)://host[:port],只填寫 origin,不能帶路徑,例如 https://oa.example.com
通配符支持一級子域名通配,例如 https://*.example.com
數量最多 20 條
留空不限制父頁面來源(不建議在生產環境使用)

簽發嵌入憑證

由你的後端調用,使用開啟了嵌入的團隊 API Key 認證。每次打開組件前簽發一個新的 code。

簽發請求

text
POST https://open.musedam.ai/api/muse/embed-code
Authorization: Bearer your_api_key
Content-Type: application/json

請求體用於指定員工,三個字段任選其一;同時傳入時優先級為 userId > loginEmail > loginPhone。

字段類型必填說明
userIdstring否MuseDAM 用戶 ID,可通過團隊與成員接口查詢
loginEmailstring否員工的 MuseDAM 登錄郵箱
loginPhonestring否員工的 MuseDAM 登錄手機號

請求示例:

bash
curl --location --request POST 'https://open.musedam.ai/api/muse/embed-code' \
--header 'Authorization: Bearer your_api_key' \
--header 'Content-Type: application/json' \
--data-raw '{
"loginEmail": "zhangsan@example.com"
}'

簽發響應

json
{
"code": "0",
"result": {
"code": "c3f1a9...",
"expiresIn": 300,
"userId": "1538720494056386560",
"orgId": "123"
}
}
字段類型說明
result.codestring一次性嵌入憑證,用於拼接嵌入頁地址
result.expiresInnumber有效期(秒),默認 300
result.userIdstring憑證對應的 MuseDAM 用戶 ID
result.orgIdstring憑證對應的團隊 ID

code 5 分鐘內有效,且只能使用一次,兌換後立即作廢。請在打開組件時實時簽發,不要緩存或複用。

簽發失敗原因

code錯誤說明處理方法
50078EMBED_API_KEY_NOT_ALLOWED只有團隊 API Key 才能簽發嵌入憑證改用團隊 API Key,不要使用個人 API Key 或應用憑證
50079EMBED_NOT_ENABLED該 API Key 未開啟嵌入組件請管理員在 API Key 詳情中開啟嵌入組件
50080EMBED_MEMBER_NOT_FOUND指定的用戶不是本團隊的有效成員有效成員指狀態為正常、管理員或待激活且未退出團隊的成員,離職成員不可用;簽發接口不會自動創建賬號

API Key 無效或已撤銷時,按錯誤處理中的認證錯誤處理。其他相關錯誤碼:

code錯誤出現場景
50081EMBED_CODE_INVALID嵌入頁兌換 code 時,code 無效、已過期或已被使用;嵌入頁會發送 musedam-embed-auth-failed
50082EMBED_ORIGIN_INVALID管理員保存「允許嵌入的域名」時格式不正確,不會在簽發或嵌入時出現

加載嵌入頁

將簽發得到的 code 拼接到嵌入頁地址,用 iframe 打開:

text
https://musedam.ai/outer/embed?code={code}&theme=light
參數必填說明
code是簽發接口返回的一次性 code,請使用 encodeURIComponent 編碼
theme否light 或 dark,只作用於本次嵌入,不寫入用戶偏好

嵌入頁域名與團隊成員登錄 MuseDAM 使用的域名一致,即 https://musedam.ai。

嵌入頁本身是透明的空白頁,只承載組件彈窗。建議 iframe 全屏覆蓋,在組件返回結果後由你的頁面隱藏或移除 iframe。code 兌換後會從嵌入頁地址欄中移除。

測試頁

聯調時可以使用嵌入組件測試頁:貼上簽發得到的 code 即可加載嵌入頁,選擇 action、編輯參數後發送,並查看生命週期事件和返回結果。

  • 測試頁與 MuseDAM 同域,加載後當前瀏覽器的 MuseDAM 登錄身份會切換為 code 對應的用戶,建議在無痕視窗中使用。
  • 如果 API Key 配置了允許嵌入的域名,需要把 https://musedam.ai 也加進去,否則會鑑權失敗。
  • 本頁面用於測試「在你的系統中嵌入 MuseDAM 組件」;嵌入應用與組件中的組件測試頁用於測試應用嵌入 MuseDAM 內部運行的場景。

生命週期事件

嵌入頁通過 postMessage 向父頁面發送以下事件,消息結構為 { source: 'musedam', type, timestamp, payload }:

type時機payload
musedam-embed-ready鑑權與初始化完成,可以開始發送 action{}
musedam-embed-auth-failedcode 缺失、無效、過期、已使用,或父頁面域名不在允許列表中{ message }
musedam-embed-auth-expired使用過程中登錄態失效{ code? }

收到 musedam-embed-auth-failed 或 musedam-embed-auth-expired 時,請讓後端重新簽發 code 並刷新 iframe 地址。嵌入頁不會跳轉到登錄頁。

調用組件

收到 musedam-embed-ready 後,通過 iframe.contentWindow.postMessage 發送 action。

消息格式

你的頁面 → 嵌入頁(請求)

typescript
{
source: "musedam-app",
target: "musedam",
type: "action",
timestamp: "2026-10-12T10:30:00.000Z",
dispatchId: "dispatch_1728700000000_abc123", // 唯一 ID,用于匹配结果
action: "assets-selector-modal-open",
args: { /* 各组件参数 */ }
}

嵌入頁 → 你的頁面(結果)

typescript
// 成功
{ type: "action_result", dispatchId, action, result: { success: true, data: { /* 结果 */ } } }
// 失败或取消
{
type: "action_result",
dispatchId,
action,
result: {
success: false,
code: "cancelled" | "forbidden" | "malformed_request" | "internal_server_error",
message: "..."
}
}
result.code含義
cancelled用戶主動取消或關閉了組件
malformed_request請求參數錯誤或格式不正確
forbiddenaction 不在可調用列表中,或用戶沒有該操作權限
internal_server_error服務器內部錯誤或其他未捕獲的異常

可調用的 action

組件action
素材選擇器assets-selector-modal-open / assets-selector-modal-close
文件夾選擇器(多選)folder-selector-modal-open / folder-selector-modal-close
文件夾選擇器(單選)single-folder-selector-modal-open / single-folder-selector-modal-close
成員選擇器member-selector-modal-open / member-selector-modal-close
上傳upload-files / sub-project-upload-complete
標籤選擇openTagSelecter / closeTagSelecter / removeTag

以上之外的 action 會直接返回 result.code = "forbidden"。*-close 用於由你的頁面主動關閉已打開的組件。嵌入會話鎖定在 code 對應的團隊,組件內不能切換團隊。

素材選擇器

素材選擇器:瀏覽、篩選並選擇資產庫中的素材。
素材選擇器:瀏覽、篩選並選擇資產庫中的素材。點擊查看大圖
  • action:assets-selector-modal-open
  • args:
typescript
{
initialSelectedAssetIds?: number[];
// 可选择的素材类型,不传则不限制
// 取值:image、video、audio、js、document、PDocument、excel、font、zip、dll、code、model、triD、url
allowedTypes?: string[];
// 各类型数量上限;limit 不传表示该类型不限数量
dataLimit?: Array<{ type: string; limit?: number }>;
// 打开时预置的筛选条件,用户仍可在组件内修改
filters?: {
types?: string[];
extensions?: string[];
size?: { min?: number; max?: number; unit?: 'KB' | 'MB' | 'GB' };
dimension?: { minWidth?: number; maxWidth?: number; minHeight?: number; maxHeight?: number };
};
}
  • result.data:{ selectedAssets: IAssetLite[] }。IAssetLite 包含 id、assetId、name、type、extension、size、width、height、downloadUrl、thumbnail、tags、folders 等字段,完整定義見嵌入應用與組件。

downloadUrl 等鏈接可能有時效。業務系統中請保存素材 ID,需要展示或下載時再通過素材管理接口獲取有效鏈接。

文件夾選擇器

文件夾選擇器:選擇一個或多個共享文件夾。
文件夾選擇器:選擇一個或多個共享文件夾。點擊查看大圖

多選:

  • action:folder-selector-modal-open
  • args:{ initialSelectedFolders?: Array<{ id: number; name: string }>; allMaterials?: boolean },allMaterials 控制是否顯示「全部素材」快速選項
  • result.data:{ selectedFolders: Array<{ id: number; name: string }>; allMaterials: boolean }

單選:

  • action:single-folder-selector-modal-open
  • args:{ initialSelectedFolder?: number | { id: number; name?: string } }
  • result.data:{ id: number; name: string }

成員選擇器

成員選擇器:按成員、部門或群組選擇。
成員選擇器:按成員、部門或群組選擇。點擊查看大圖
  • action:member-selector-modal-open
  • args:
typescript
{
selectedItems?: {
members?: Array<{ id: string; name: string }>;
departments?: Array<{ id: string; name: string }>;
groups?: Array<{ id: string; name: string }>;
};
}
  • result.data:
typescript
{
members: Array<{ id: string; name: string; departmentsName?: string; avatarUrl?: string }>;
departments: Array<{ id: string; name: string }>;
groups: Array<{ id: string; name: string }>;
}

文件上傳

上傳分兩步:先用 upload-files 上傳文件,業務處理完成後再用 sub-project-upload-complete 通知 MuseDAM 正式入庫。

第一步:upload-files

typescript
// args
{
files: File[]; // 必填,可通过 <input type="file"> 获取
folderId?: number; // 目标文件夹 ID,可先用单选文件夹选择器获取
uploadSource?: string; // 上传来源标识
subProjectId?: string; // 推荐填写,用于区分不同业务的上传
}
// result.data
{
uploadedFiles: Array<{
key: string; // 文件唯一标识,第二步需要使用
fileName: string;
fileSize: number;
fileType: string;
uploadTime: string;
url?: string;
}>;
failedFiles?: Array<{ fileName: string; error: string }>;
}

第二步:sub-project-upload-complete

typescript
// args
{
subProjectId: string; // 与上传时一致
uploadKeys: Array<{ key: string; fileName: string; fileSize: number; fileType: string; uploadTime: string; url?: string }>;
}
// result.data
{
processedFiles: Array<{ key: string; fileName: string; status: 'success' | 'failed'; error?: string }>;
}

部分文件失敗時 result.success 仍為 true,請逐個檢查 failedFiles 和 processedFiles[].status。

標籤選擇器

標籤選擇器以浮層形式顯示在指定位置,適合在你的頁面中為內容打 MuseDAM 標籤。

actionargs說明
openTagSelecter{ rect: { left: number; top: number; width?: number; height?: number } }在視口座標 rect 旁打開標籤浮層
closeTagSelecter無關閉標籤浮層
removeTag{ tagId: number }從當前已選標籤中移除一個標籤

標籤選擇器不返回 action_result。用戶每次修改標籤,嵌入頁都會發送 { source: 'musedam', type: 'action', action: 'updateTags', args: { tags } },請以最後一次收到的 tags 為準。

完整示例

服務端簽發 code

以 Node.js 為例,API Key 只保存在服務端環境變量中:

javascript
// POST /api/musedam/embed-code —— 你自己的后端接口,需校验当前登录用户
app.post('/api/musedam/embed-code', requireLogin, async (req, res) => {
const response = await fetch('https://open.musedam.ai/api/muse/embed-code', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MUSEDAM_API_KEY}`,
'Content-Type': 'application/json',
},
// 只为当前登录员工签发,不要直接使用前端传入的邮箱
body: JSON.stringify({ loginEmail: req.user.email }),
})
const body = await response.json()
if (String(body.code) !== '0') {
return res.status(400).json({ message: body.message })
}
res.json({ code: body.result.code })
})

前端打開組件

javascript
const MUSEDAM_ORIGIN = 'https://musedam.ai'
async function openMuseDAM(action, args) {
// 1. 每次打开都向自己的后端获取新的 code
const { code } = await fetch('/api/musedam/embed-code', { method: 'POST' }).then((r) => r.json())
// 2. 创建全屏 iframe
const iframe = document.createElement('iframe')
iframe.style.cssText = 'position:fixed;inset:0;width:100%;height:100%;border:0;z-index:9999'
iframe.src = `${MUSEDAM_ORIGIN}/outer/embed?code=${encodeURIComponent(code)}&theme=light`
document.body.appendChild(iframe)
const dispatchId = `dispatch_${Date.now()}_${Math.random().toString(36).slice(2)}`
return new Promise((resolve, reject) => {
function cleanup() {
window.removeEventListener('message', onMessage)
iframe.remove()
}
function onMessage(event) {
// 3. 只处理来自 MuseDAM 嵌入页的消息
if (event.origin !== MUSEDAM_ORIGIN || event.source !== iframe.contentWindow) return
const data = event.data || {}
switch (data.type) {
case 'musedam-embed-ready':
// 4. 初始化完成后发送 action
iframe.contentWindow.postMessage(
{
source: 'musedam-app',
target: 'musedam',
type: 'action',
timestamp: new Date().toISOString(),
dispatchId,
action,
args,
},
MUSEDAM_ORIGIN,
)
break
case 'musedam-embed-auth-failed':
case 'musedam-embed-auth-expired':
cleanup()
reject(new Error(data.payload?.message || data.type))
break
case 'action_result':
// 5. 按 dispatchId 匹配结果
if (data.dispatchId !== dispatchId) return
cleanup()
data.result?.success
? resolve(data.result.data)
: reject(Object.assign(new Error(data.result?.message), { code: data.result?.code }))
break
}
}
window.addEventListener('message', onMessage)
})
}
// 使用:最多选择 5 张图片
openMuseDAM('assets-selector-modal-open', { allowedTypes: ['image'], dataLimit: [{ type: 'image', limit: 5 }] })
.then(({ selectedAssets }) => console.log('已选择', selectedAssets))
.catch((error) => error.code !== 'cancelled' && console.error(error))

安全建議

  • API Key 只能保存在後端,不能出現在 iframe 地址、前端代碼或瀏覽器存儲中。
  • 後端只為當前已登錄的員工簽發 code,員工標識應取自你的登錄會話,不要信任前端傳入的郵箱或手機號。
  • code 5 分鐘內有效且只能使用一次。不要記錄到日誌、埋點或分享鏈接中。
  • 在生產環境中配置「允許嵌入的域名」,只填寫實際承載 iframe 的頁面 origin。
  • 接收消息時校驗 event.origin 和 event.source;發送消息時指定 MuseDAM 的 origin,不要使用 '*'。
  • 員工離職或被移出團隊後,將無法再為其簽發或兌換 code。不再需要嵌入時,請關閉開關或撤銷 API Key。

常見問題

收到 musedam-embed-auth-failed 怎麼辦?

依次檢查:code 是否超過 5 分鐘、是否已被使用過(例如頁面刷新後重複使用了同一個地址)、父頁面 origin 是否在「允許嵌入的域名」中(注意協議和端口)。

可以把 iframe 預加載以加快打開速度嗎?

可以在用戶即將操作時提前簽發 code 並加載 iframe,收到 musedam-embed-ready 後再顯示。注意 code 5 分鐘有效,過期後需要重新簽發。

組件中能看到哪些素材和成員?

與員工本人登錄 MuseDAM 時一致,按該員工的團隊成員權限展示。嵌入會話固定在簽發 code 的團隊內。

MuseDAM Developer PlatformAPI · Integrations · MCP
    外部系統嵌入組件 | MuseDAM Developers