為你的Fabric應用程式設定Fabric SSO認證

為 Fabric 應用程式設定 Fabric 單點登入(SSO),讓使用者能透過 Fabric 入口網站使用 Microsoft Entra ID 登入。 本文說明交接流程,並展示如何啟用部署應用程式所需的設定與 SDK 整合。

先決條件

Fabric SSO 的運作原理

Fabric 單一登入(SSO)會在您的應用程式與 Fabric 入口網站之間,透過安全的postMessage式交接機制運作。 沒有重定向或回撥頁面:

  1. 你的應用程式會在彈出式視窗中開啟 Fabric 入口網站,並註冊 postMessage 監聽器。
  2. 使用者透過 Fabric 入口網站內的 Microsoft Entra ID 進行認證。
  3. Fabric擴充功能會透過 window.opener.postMessage() 把交接碼回傳給你的應用程式。
  4. SDK 會將 handoff 代碼交換成 Rayfin 會話令牌並建立會話。
  5. 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.ymlallowedRedirectUris 的其中一個項目。
  • 匯入資料來自 @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>;

實作四步驟認證瀑布式:

  1. 如果已經認證過,會回傳現有的會話。
  2. 嘗試透過刷新標記進行靜默刷新。
  3. 嵌入模式——若運行於Fabric iframe,則透過 postMessage 取得父框架的會話。
  4. 以彈出視窗(彈出流程)開啟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 設定為正確的 baseUrlpublishableKey。 回調分頁和原始分頁必須共享相同的起點BroadcastChannellocalStorage,才能運作。

驗證在長時間延遲後失敗

登入流程在 5 分鐘後終止。 如果你開始登入流程但沒在這段時間內完成,流程就會失敗。 關閉彈出視窗,再次選擇登入按鈕開始新的流程。