Настройте аутентификацию SSO для вашего приложения Fabric

Настройте единый вход Fabric для приложения Fabric, чтобы пользователи могли войти с помощью Microsoft Entra ID через портал Fabric. В этой статье объясняется поток передачи и показано, как включить необходимую настройку и интеграцию пакета SDK для развернутых приложений.

Необходимые условия

Как работает единый вход Fabric

Для единого входа (SSO) в Fabric используется безопасный механизм передачи на основе postMessage между вашим приложением и порталом Fabric. Нет страницы перенаправления или обратного вызова:

  1. Приложение открывает портал Fabric во всплывающем колонте и регистрирует прослушиватель postMessage.
  2. Пользователь проходит проверку подлинности через Microsoft Entra ID на портале Fabric.
  3. Расширение Fabric отправляет код для передачи обратно в ваше приложение через window.opener.postMessage().
  4. Пакет SDK обменивается кодом передачи для маркеров сеанса Rayfin и создает сеанс.
  5. Всплывающее окно Fabric закрывается автоматически.

Безопасность потока обеспечивается с помощью PKCE (Proof Key for Code Exchange), одноразовых значений state и postMessage проверки источника, чтобы предотвратить перехват кода авторизации и межсайтовую подделку запросов.

Включить аутентификацию Fabric

Добавьте конфигурацию проверки подлинности Fabric в файл rayfin/rayfin.yml:

services:
  auth:
    enabled: true
    allowedRedirectUris:
      - http://localhost:5173
    fabric:
      enabled: true

Для развернутых приложений повторно разверните их, чтобы применить обновленные настройки:

npx rayfin up

Для развернутых приложений npx rayfin up добавляет URL-адрес обратного вызова развернутого приложения в allowedRedirectUris.

Установите поставщик проверки подлинности Fabric (необязательно)

Проекты, созданные с помощью npm create @microsoft/rayfin@latest, уже включают @microsoft/rayfin-auth-provider-fabric. Установите его вручную, только если вы добавляете проверку подлинности Fabric в проект, который еще не имеет пакета:

npm install @microsoft/rayfin-auth-provider-fabric

Добавьте вход и регистрацию в ваше приложение

Единый вход Fabric использует один API как для входа, так и для регистрации: ensureSignedInWithFabric(). Когда пользователь впервые входит в систему, Fabric автоматически создает для него сеанс Rayfin на основе его удостоверения Microsoft Entra ID — отдельный вызов для регистрации не требуется. Та же ветка кода обрабатывает и вернувшихся пользователей.

Этот код можно добавить вручную или создать с помощью 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 должен содержать только origin (схему и хост, без пути) — например, 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

Если вы используете GitHub Copilot в VS Code, откройте Copilot Chat в проекте Fabric Apps и используйте, например, такие запросы, чтобы сгенерировать каркас кода аутентификации. Copilot использует шаблоны навыка Rayfin, входящего в состав расширения Fabric для VS Code.

Goal Пример запрос 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-хук с учетом аутентификации 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 — это origin без дополнительных компонентов и соответствует одной из записей в allowedRedirectUris в rayfin/rayfin.yml.
  • Импорт выполняется из @microsoft/rayfin-auth-provider-fabric (а не из устаревших вспомогательных функций обратного вызова).

Используйте встроенный режим в iframe Fabric

Когда приложение загружается внутри Fabric iframe (например, когда пользователь открывает его с портала Fabric), используйте внедренный режим вместо всплывающего потока:

  • Встроенный режим получает сеанс через postMessage от родительского фрейма.
  • Он не открывает всплывающее окно и не требует пользовательского жеста, поэтому его можно безопасно вызывать при загрузке страницы.
  • SDK автоматически определяет встроенный режим по параметру ?fabricEmbedded=true в URL-адресе. Вы также можете принудительно включить это, установив 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() также автоматически пытается использовать встроенный режим, прежде чем перейти к сценарию со всплывающим окном.

Использование проверки подлинности Fabric в React

Создайте пользовательский хук, который объединяет вход, регистрацию и выход:

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

ensureSignedInWithFabric

function ensureSignedInWithFabric(
  auth: Auth,
  options: FabricAuthOptions
): Promise<OpaqueSession>;

Реализует четырёхэтапную последовательность аутентификации:

  1. Возвращает существующий сеанс, если он уже прошел проверку подлинности.
  2. Пытается выполнить тихое обновление с помощью токена обновления.
  3. Встроенный режим — при запуске внутри iframe Fabric получает сеанс через postMessage из родительского фрейма.
  4. Открывает портал Fabric во всплывающем окне (сценарий со всплывающим окном) и ожидает передачи управления postMessage.

Шаги 1–3 можно безопасно вызывать при загрузке страницы. Шаг 4 открывает всплывающее окно и должен выполняться внутри обработчика жестов пользователя.

FabricAuthOptions

Property Тип Description
workspaceId string Идентификатор рабочей области Fabric.
projectId string Идентификатор элемента приложения Fabric.
fabricPortalUrl string Базовый URL-адрес портала Fabric (например, https://app.fabric.microsoft.com).
returnOrigin string Источник доставки postMessage для вашего приложения (например, window.location.origin). Должен быть исходным источником (схема и узел, без пути).
fabricEmbedded boolean (необязательно) Принудительно включить встроенный режим. Автоматически определено по ?fabricEmbedded=true в URL-адресе.

Вспомогательные функции

Function Description
initEmbeddedAuth(auth, options) Встроенная аутентификация, безопасная при загрузке страницы. Возвращает сеанс, если выполняется внутри iframe Fabric, или null в противном случае.
initiateFabricLogin(auth, options) Поток всплывающего окна низкого уровня. Открывает портал Fabric во всплывающем окне с параметрами PKCE и ожидает передачу postMessage.
isEmbeddedMode(options) Возвращает true, если приложение работает в внедренном режиме (Fabric iframe).

Функции безопасности

  • PKCE S256 — каждый поток создает средство проверки криптографического кода и вызов, чтобы предотвратить перехват кода авторизации.
  • Параметр state (nonce) — случайное значение nonce привязывает ответ передачи к исходной вкладке, предотвращая межсайтовую подделку запросов.
  • postMessage Проверка источника — пакет SDK проверяет event.origin входящие сообщения и отклоняет сообщения из непредвиденных источников.
  • Автоматическая очистка — срок действия PKCE истекает через 5 минут и собирается мусор в следующем потоке.
  • Время ожидания потока — время ожидания всплывающего окна истекает через 5 минут, если сообщение об отработке не получено.

Устранение проблем с проверкой подлинности

Браузер заблокировал окно портала Fabric. Убедитесь, что ensureSignedInWithFabric() вызывается из синхронного обработчика действия пользователя (например, кнопки onClick). Не вызывайте его при загрузке страницы или внутри асинхронной цепочки до взаимодействия пользователя.

Сеанс не сохраняется

Убедитесь, что для RayfinClient заданы правильные baseUrl и publishableKey. Для работы BroadcastChannel и localStorage вкладка обратного вызова и исходная вкладка должны иметь один и тот же источник.

Проверка подлинности завершается ошибкой после длительной задержки

Срок действия потока входа истекает через 5 минут. Если вы запускаете процесс входа, но не завершаете его в течение этого времени, поток завершается сбоем. Закройте всплывающее окно и снова нажмите кнопку входа, чтобы запустить новый поток.