為 Fabric 應用程式設定 Fabric 單點登入(SSO),讓使用者能透過 Fabric 入口網站使用 Microsoft Entra ID 登入。 本文說明交接流程,並展示如何啟用部署應用程式所需的設定與 SDK 整合。
先決條件
- 一個啟用認證的 Fabric Apps 專案。 請參見「設定認證」。
- 一個已部署的 Fabric Apps 項目。 請參見 部署至 Fabric。
Fabric SSO 的運作原理
Fabric 單一登入(SSO)會在您的應用程式與 Fabric 入口網站之間,透過安全的postMessage式交接機制運作。 沒有重定向或回撥頁面:
- 你的應用程式會在彈出式視窗中開啟 Fabric 入口網站,並註冊
postMessage監聽器。 - 使用者透過 Fabric 入口網站內的 Microsoft Entra ID 進行認證。
- Fabric擴充功能會透過
window.opener.postMessage()把交接碼回傳給你的應用程式。 - SDK 會將 handoff 代碼交換成 Rayfin 會話令牌並建立會話。
- Fabric 彈出視窗會自動關閉。
此流程透過 PKCE(程式碼交換證明金鑰)、state nonce,以及 postMessage 來源驗證加以保護,以防止授權碼遭攔截及跨站請求偽造。
啟用 Fabric 認證
將Fabric認證設定加入你的 rayfin/rayfin.yml 檔案:
services:
auth:
enabled: true
allowedRedirectUris:
- http://localhost:5173
fabric:
enabled: true
對於已部署的應用程式,請重新部署以推送更新的設定:
npx rayfin up
對於已部署的應用程式, npx rayfin up 會將你的部署應用程式回調網址加到 allowedRedirectUris。
安裝 Fabric 認證提供者(可選)
使用 npm create @microsoft/rayfin@latest 建立的專案已經包含 @microsoft/rayfin-auth-provider-fabric。 只有在你要為尚未安裝該套件的專案加裝 Fabric 認證時,才手動安裝:
npm install @microsoft/rayfin-auth-provider-fabric
在你的應用程式中新增登入和註冊
Fabric SSO 使用單一 API 進行登入與註冊:ensureSignedInWithFabric()。 當使用者首次登入時,Fabric 會根據他們的 Microsoft Entra ID 身份自動為他們設定 Rayfin 會話——沒有額外的註冊呼叫。 相同的程式碼路徑也用於處理回傳使用者。
你可以手動新增這些程式碼,或用 GitHub Copilot 在 VS Code 中產生。
手動新增登入功能
在使用者手勢處理常式中呼叫 ensureSignedInWithFabric()(例如按鈕選取):
import { RayfinClient } from '@microsoft/rayfin-client';
import { ensureSignedInWithFabric } from '@microsoft/rayfin-auth-provider-fabric';
const client = new RayfinClient({
baseUrl: import.meta.env.VITE_RAYFIN_API_URL,
publishableKey: import.meta.env.VITE_RAYFIN_PUBLISHABLE_KEY,
});
const fabricOptions = {
workspaceId: import.meta.env.VITE_FABRIC_WORKSPACE_ID,
projectId: import.meta.env.VITE_FABRIC_ITEM_ID,
fabricPortalUrl: import.meta.env.VITE_FABRIC_PORTAL_URL,
returnOrigin: window.location.origin,
};
async function handleSignIn() {
// Signs in existing users and provisions new users on first sign-in.
const session = await ensureSignedInWithFabric(client.auth, fabricOptions);
if (session.isAuthenticated && session.user) {
console.log('Signed in as:', session.user.email);
}
}
該函式必須由同步使用者手勢處理程序呼叫,以避免彈出視窗阻擋。 在頁面載入時,或在使用者互動前的非同步呼叫鏈中呼叫它,都會觸發瀏覽器的彈出式視窗防護機制。
returnOrigin 必須是裸原點(方案與宿主,無路徑)——例如, https://app.contoso.com。 SDK 利用它來驗證進入 postMessage 的事件。
手動新增登出功能
呼叫 client.auth.signOut() 結束會話並清除快取的標記:
async function handleSignOut() {
await client.auth.signOut();
console.log('Signed out');
}
訂閱會話變更,以便在登入或登出完成後更新你的介面:
client.auth.onSessionChange((session) => {
console.log('Session changed:', session?.isAuthenticated ? 'signed in' : 'signed out');
});
使用 GitHub Copilot 產生登入與註冊
如果你使用 VS Code 中的 GitHub Copilot,請在你的 Fabric Apps 專案中開啟 Copilot Chat,並使用如下提示來建立驗證程式碼的基本架構。 Copilot 依循隨 Fabric VS Code 擴充功能附帶的 Rayfin 技能中的模式。
| 目標 | Copilot 提示 範例 |
|---|---|
| 新增登入按鈕 | Add a Sign in with Fabric button to my React app using ensureSignedInWithFabric from @microsoft/rayfin-auth-provider-fabric. Read workspaceId, projectId, and fabricPortalUrl from VITE_* env vars and set returnOrigin to window.location.origin. |
| 新增登出按鈕 | Add a Sign out button that calls client.auth.signOut() and updates the UI when the session ends. |
| 新增一個可感知驗證狀態的 React Hook | Create a useFabricAuth React hook that exposes session, signIn, signOut, and isAuthenticated, using ensureSignedInWithFabric and client.auth.onSessionChange. |
| 支援嵌入式模式 | Update my app's entry point to call initEmbeddedAuth on page load so users signed in through the Fabric portal don't have to click Sign in again. |
| 控管路由 | Wrap the /dashboard route so it calls ensureSignedInWithFabric before rendering and redirects unauthenticated users to a sign-in page. |
Copilot 產生程式碼後,請檢視修改內容並確保:
-
ensureSignedInWithFabric()呼叫會在使用者手勢處理常式中執行(例如onClick),而非在頁面載入時。 -
returnOrigin是裸來源,並且符合rayfin/rayfin.yml中allowedRedirectUris的其中一個項目。 - 匯入資料來自
@microsoft/rayfin-auth-provider-fabric(不是已棄用的回撥輔助工具)。
在 Fabric iframe 內使用嵌入式模式
當你的應用程式載入 Fabric iframe 時(例如使用者從 Fabric 入口開啟時),請使用嵌入模式取代彈出式流程:
- 嵌入模式會透過
postMessage從父框架取得工作階段。 - 它不會跳出視窗,也不需要使用者手勢,所以在頁面載入時呼叫是安全的。
- SDK 會從 URL 中的
?fabricEmbedded=true自動偵測是否為嵌入模式。 你也可以透過在選項中設定fabricEmbedded: true來強制啟用它。
在應用程式啟動初期盡早呼叫 initEmbeddedAuth():
import { initEmbeddedAuth } from '@microsoft/rayfin-auth-provider-fabric';
import { client } from './lib/rayfin';
const session = await initEmbeddedAuth(client.auth, {
workspaceId: import.meta.env.VITE_FABRIC_WORKSPACE_ID,
projectId: import.meta.env.VITE_FABRIC_ITEM_ID,
fabricPortalUrl: import.meta.env.VITE_FABRIC_PORTAL_URL,
returnOrigin: window.location.origin,
});
if (session) {
console.log('Signed in via embedded mode:', session.user?.email);
}
initEmbeddedAuth() 當應用程式沒有在嵌入式模式下運行時,它會回傳 null ,所以無條件呼叫是安全的。
ensureSignedInWithFabric() 也會自動嘗試嵌入模式,然後再回到彈出式流程。
在 React 中使用 Fabric 認證
建立一個整合登入、註冊與登出的自訂掛鉤:
import { useState, useEffect, useCallback } from 'react';
import { ensureSignedInWithFabric } from '@microsoft/rayfin-auth-provider-fabric';
import { client } from './lib/rayfin';
const fabricOptions = {
workspaceId: import.meta.env.VITE_FABRIC_WORKSPACE_ID,
projectId: import.meta.env.VITE_FABRIC_ITEM_ID,
fabricPortalUrl: import.meta.env.VITE_FABRIC_PORTAL_URL,
returnOrigin: window.location.origin,
};
export function useFabricAuth() {
const [session, setSession] = useState(client.auth.getSession());
useEffect(() => client.auth.onSessionChange(setSession), []);
// Signs in existing users and provisions new users on first sign-in.
const signIn = useCallback(async () => {
const result = await ensureSignedInWithFabric(client.auth, fabricOptions);
setSession(result);
return result;
}, []);
const signOut = useCallback(async () => {
await client.auth.signOut();
}, []);
return {
session,
signIn,
signOut,
isAuthenticated: session?.isAuthenticated ?? false,
};
}
在你的組件中使用這個鉤子:
function App() {
const { isAuthenticated, signIn, signOut } = useFabricAuth();
if (!isAuthenticated) {
return <button onClick={signIn}>Sign in with Fabric</button>;
}
return (
<>
<Dashboard />
<button onClick={signOut}>Sign out</button>
</>
);
}
API 參考資料
確保已使用 Fabric 登入
function ensureSignedInWithFabric(
auth: Auth,
options: FabricAuthOptions
): Promise<OpaqueSession>;
實作四步驟認證瀑布式:
- 如果已經認證過,會回傳現有的會話。
- 嘗試透過刷新標記進行靜默刷新。
- 嵌入模式——若運行於Fabric iframe,則透過
postMessage取得父框架的會話。 - 以彈出視窗(彈出流程)開啟Fabric傳送門,並等待
postMessage交接。
步驟 1 至 3 可在頁面載入時安全呼叫。 步驟 4 會開啟一個彈出視窗,必須在使用者手勢處理器中執行。
FabricAuthOptions
| Property | 類型 | Description |
|---|---|---|
workspaceId |
string |
Fabric 工作區的 ID。 |
projectId |
string |
Fabric 應用程式的商品 ID。 |
fabricPortalUrl |
string |
Fabric入口網站的基礎網址(例如 https://app.fabric.microsoft.com)。 |
returnOrigin |
string |
你的應用程式用於傳送 postMessage 的來源(例如 window.location.origin)。 必須是裸原點(方案和主機,沒有路徑)。 |
fabricEmbedded |
boolean (選用) |
強制內嵌模式。 從 URL 中的 ?fabricEmbedded=true 自動偵測。 |
輔助函式
| 功能 | Description |
|---|---|
initEmbeddedAuth(auth, options) |
頁面載入安全內嵌認證。如果在Fabric iframe內運行,則回傳會話;否則則回傳null。 |
initiateFabricLogin(auth, options) |
低階彈出式視窗流程。 在快顯視窗中使用 PKCE 參數開啟 Fabric 入口網站,並監聽 postMessage 交接。 |
isEmbeddedMode(options) |
若應用程式以嵌入式模式(Fabric iframe)運行,則回傳 true。 |
安全特徵
- PKCE S256 – 每個流程都會產生密碼驗證器與挑戰,以防止授權碼被攔截。
- 狀態 nonce-隨機 nonce 會將交接回應與發起該流程的原始分頁綁定,防止跨站請求偽造。
-
postMessage來源驗證 – SDK 會驗證event.origin收到的訊息,並拒絕來自意外來源的訊息。 - 自動清理 ——PKCE 狀態在 5 分鐘後失效,並在下一次流程中進行垃圾回收。
- 流程逾時 – 若未收到交接訊息,快顯視窗流程將於 5 分鐘後逾時。
針對驗證問題進行疑難排解
彈出視窗被封鎖
瀏覽器封鎖了 Fabric 入口視窗。 Ensure ensureSignedInWithFabric() 是由同步使用者手勢處理程式(例如按鈕 onClick)呼叫的。 不要在頁面載入時或使用者互動前在非同步鏈內呼叫它。
會話無法持續
確認 該 RayfinClient 設定為正確的 baseUrl 和 publishableKey。 回調分頁和原始分頁必須共享相同的起點BroadcastChannellocalStorage,才能運作。
驗證在長時間延遲後失敗
登入流程在 5 分鐘後終止。 如果你開始登入流程但沒在這段時間內完成,流程就會失敗。 關閉彈出視窗,再次選擇登入按鈕開始新的流程。