把一個 AI agent 平台從『自己玩』推到『給全公司幾千、幾萬人用』,第一道真正的牆不是模型、不是 GPU,而是授權:誰能問什麼、誰不能看什麼。而且台灣多數企業會要求接 Azure AD(Entra ID) 做單一登入。這篇把我實際把 Dify + n8n 推向企業授權時,整理出來的架構一次講清楚 —— 全是通用做法,不含任何公司內部資訊。
重點摘要
- Dify 自己扛不了企業授權:對外端點只有一把靜態 token、跑的還是最舊的 MCP 協定(2024-11-05)、沒有原生 OAuth —— 所以 Azure AD(Entra ID)這關一定要加在它前面。
- 先分清認證(authN,你是誰)≠ 授權(authZ,你能碰什麼);身分只能從 Entra 發,中間的 n8n 只能『驗』token、發不出身分。
- 同一個 n8n 同時接『人登入(auth-code)』與『機器(M2M)』;但 M2M 沒有人的身分、只有一段固定資料範圍,不能拿去套職級分級。
- 授權要集中:政策放 Entra roles / 中央 PDP、n8n 當執行點(PEP)、Dify 待信任邊界後不做授權 —— 別在每個 app 重造一套 AD。
- 分級 RAG 要分知識庫(RAG 靠相似度撈、不管權限);而且 MCP 只放最外層、內部串接用 REST API。
痛點:一放大到全公司,馬上撞授權
自己一個人用 Dify,權限根本不是問題 —— 反正資料都是你自己的。但只要對象變成『整間公司』,同一個問題會有完全不同的正確答案:HR 問薪資該看得到、一般員工問同一題不該看到。agent 平台一放大,第一個炸開的就是授權,而不是技術能不能跑。

記住這張圖的分層就好:門在外、能力在後。呼叫方帶著 Entra 發的 token 進來,前面那層驗身分、決定放不放行,驗過之後才用一個內部 token 去打後面的 Dify。Dify 從頭到尾不碰身分、也不做授權。
第一個事實:Dify 自己扛不了 AAD
這是實測得到、而不是猜的結論:Dify 本身做不了企業級授權。
- 它對外的端點,認證就只有一把靜態 token —— 拿到就是拿到,沒有隨人變的身分。
- 它把 app 開成 MCP server 時,跑的還是 MCP 最初那版協定(2024-11-05),連原生 OAuth 都沒有。
- 所以結論很直接:Azure AD / SSO 這關,不可能靠 Dify 自己,一定要在它前面加一層擋。
先分清楚:你是誰 ≠ 你能碰什麼
談授權前,先把兩個最常被攪在一起的東西分開,不然權限模型一定會歪:
| 是什麼 | 誰做 | |
|---|---|---|
| authN 認證 | 證明『你是誰』 | Azure AD / Entra |
| authZ 授權 | 決定『你能碰哪些資料 / 功能』 | PEP(n8n)+ 集中政策 |
AAD 幫你確認身分;至於這個身分能看什麼,是另一層要決定的事。
身分只能從 Entra 發,n8n 生不出來
想通這個觀念,後面全順:代表身分的那張 token 只有 Entra 能發。中間的 n8n 只能『驗』你給它的 token,它變不出身分來。
所以呼叫方一定要『先自己拿到一張 token』,再拿去問 n8n。拿 token 這步躲不掉 —— 但它不是要你另建系統,只是跟 Entra 換一張證而已。怎麼換,分成兩種情況,這正是下一段的重點。
同一個 n8n,人與機器兩種入口都接
很多人以為要嘛做給人、要嘛做給機器 —— 其實同一個 n8n 可以同時接兩種呼叫方,只是拿 token 的方式不同。

| 呼叫方 | 怎麼拿 token | 拿到的身分 |
|---|---|---|
| 👤 人 / 員工 | 開 /login → 導去 Entra 登入 → Entra 帶著 code 回 n8n 的一個網址(redirect URI)→ n8n 用 code 換 token(auth-code flow) | 某個員工的身分 → 可依職級分級 |
| 🤖 機器 / service | 用自己的憑證、或平台自動發的受管身分,直接拿 token(M2M / client credentials,沒有登入畫面) | app 身分,背後沒有人 |
關鍵坑:機器沒有『人』的身分
這是最容易做錯的一個點,一定要講白:
- 人登入拿到的是『某個員工』的身分,所以你可以依他的職級 —— 一般、經理、處長 —— 做分級。
- 機器對機器(M2M)拿到的是『app 身分』,它背後沒有人。
- 所以 M2M 不是在做『分級』,而是『這個系統被授權讀哪一份資料』,通常是一段固定範圍。
授權集中:別在 Dify 養第二套權限
那『誰能看哪份資料』這種細授權,放哪?這是整套最容易做錯的地方。答案是:集中。

- 政策放一個地方 —— 用 Entra 的 App Roles / Groups,或再加一個中央政策引擎(PDP,如 OPA)。
- n8n 當執行點(PEP):收到 token 就讀它的角色、去問政策『這個人能碰這份嗎』,能才放行。
- Dify 待信任邊界後,不做授權 —— 不要在 Dify 裡再養一套權限表。
分級 RAG:敏感內容一定要『分知識庫』
一個 RAG 特有、而且很容易出包的坑:RAG 是靠語意相似度撈文件的,它預設完全不管權限。
如果你把『薪資、財務』這種敏感內容,跟一般公開手冊放在同一個知識庫,一般員工問一個相關問題,檢索可能就撈到敏感那塊、塞進答案漏出去。
MCP 在外、API 在內
最後一個能幫你省掉一堆麻煩的架構要點:
- n8n 到 Dify 是『內部』,用 Dify 的 REST API(
/v1/chat-messages)打就好,根本不用把 Dify 做成 MCP。 - n8n 手上放各職級那幾把 Dify API key,驗完身分、依職級,挑對應那把 key 去打。
- MCP 只放最外層 —— 而且只有當你要給外部 AI client(像 Claude、Cursor)標準化探索工具時才值得。
可以直接匯入的 n8n sample
把上面的『人登入』版做成一個可匯入的 n8n workflow:員工開 /login → 導去 Entra → callback 用 code 換『員工』token → 讀 roles 分流 → 打對應職級的 Dify app。核心是那顆讀 token、決定 level 的 Code node(PEP):
// 拿到員工 token,讀 roles → level → 挑對應的 Dify key(PEP)
// ⚠️ 生產環境:要驗簽(Entra JWKS)+ 檢查 aud / exp;此處只解 payload 示範路由
const tok = $('用 code 換員工 token').first().json.access_token;
const payload = JSON.parse(Buffer.from(tok.split('.')[1], 'base64url').toString());
const roles = payload.roles || [];
let level = 'general', keyEnv = 'DIFY_KEY_GENERAL';
if (roles.includes('RAG.Sensitive')) { level = 'sensitive'; keyEnv = 'DIFY_KEY_SENSITIVE'; }
else if (roles.includes('RAG.Manager')) { level = 'manager'; keyEnv = 'DIFY_KEY_MANAGER'; }
return [{ json: {
level,
user: payload.preferred_username || payload.oid,
difyKey: $env[keyEnv], // 依職級挑對應那把 key
difyUrl: ($env.DIFY_BASE) + '/v1/chat-messages' // 內部走 REST,不用 MCP
} }];
完整的兩個 workflow(人登入 auth-code / 機器 M2M 自驗)+ 情境式手冊,放在課程的架構頁與使用手冊:企業授權架構頁、Dify 情境式手冊 Part 四(可匯入的 n8n sample)。
發佈留言