Использование MSAL в приложениях iframed

По умолчанию MSAL предотвращает перенаправления всего фрейма на конечную точку аутентификации Microsoft Entra ID, когда приложение отображается внутри iframe, а значит, вы не можете использовать API перенаправления для взаимодействия пользователя с IdP:

  • Это ограничение применяется, так как Microsoft Entra ID отказывается отображать любой запрос, требующий взаимодействия с пользователем (например, записи учетных данных, согласия, выхода и т. д.) в iframe, вызывая X-FRAME OPTIONS SET TO DENYошибку, меру, предпринятую для предотвращения атак щелчка.
  • Вместо этого вам придется полагаться на всплывающие API MSAL, если требуется взаимодействие с пользователем, и (или) автоматические API (ssoSilent(), acquireTokenSilent()если взаимодействие с пользователем можно избежать).
  • Аналогичным образом вам потребуется использовать API logoutPopup() для выхода из системы (:warning: если ваше приложение использует версию msal-browser ниже v2.13, обязательно обновите её и замените API logout(), так как оно попытается выполнить перенаправление всего фрейма в Microsoft Entra ID).
  • При использовании всплывающих API необходимо учитывать все ограничения песочницы , введенные родительским приложением. В частности, родительское приложение должно установить флаг allow-popups, если для iframe включена песочница.

Azure AD B2C предоставляет встроенную процедуру входа, которая позволяет отображать настраиваемый интерфейс входа в iframe. Так как MSAL запрещает перенаправление в iframe по умолчанию, необходимо задать для параметра конфигурации allowRedirectInIframeзначение true , чтобы использовать эту функцию. Обратите внимание, что включение этого параметра для приложений на Microsoft Entra ID не рекомендуется из-за указанного выше ограничения.

Ограничения браузера

Так как файлы cookie сеанса Microsoft Entra в iframe считаются сторонними файлами cookie, некоторые браузеры (например, Safari или Chrome в режиме инкогнито) блокируют или очищают эти файлы cookie по умолчанию. Это повлияет на интерфейс единого входа для приложений iframed, так как у них не будет доступа к файлам cookie сеанса idP (см. раздел "Единый вход").

Кроме того, когда сторонние файлы cookie отключены в Chrome, приложения MSAL, встроенные в iframe, не будут иметь доступа к локальному хранилищу или хранилищу сеанса. В этом случае MSAL перейдёт на хранилище в памяти.

Единый вход

Вы можете обеспечить единый вход между приложениями, встроенными в iframe, и родительским приложением как с общим источником, так и с разными источниками, если передать подсказку учетной записи из родительского приложения в приложение, встроенное в iframe.

Приложения с одинаковым источником

Приложения в iframe и родительские приложения, имеющие общий источник, могут иметь доступ к одному и тому же экземпляру кэша MSAL.js и выполнять вход без запросов учетных данных при условии, что оба приложения настроят MSAL на использование локального хранилища в качестве хранилища кэша. Дополнительные сведения: единый вход с помощью MSAL.js

Приложения с перекрестным источником

Iframed и родительские приложения с перекрестным источником могут использовать API ssoSilent() для достижения единого входа. Для этого родительское приложение должно передать учетную запись, имя входаHint (имя пользователя) или идентификатор сеанса (sid) в приложение iframed.

Приложения могут пытаться использовать ssoSilent без указанных выше параметров. Однако следует учитывать, что при использовании ssoSilent без предоставления какой-либо информации о пользовательском сеансе существуют дополнительные соображения.

Для обмена данными между iframed и родительскими приложениями можно рассмотреть несколько вариантов:

  • Строки запроса можно добавить в источник iframe в родительском приложении и получить их позже в дочернем:
// Create the main myMSALObj instance
// configuration parameters are located at authConfig.js
const myMSALObj = new msal.PublicClientApplication({
    auth: {
        clientId: "ENTER_CLIENT_ID",
        authority: "https://login.microsoftonline.com/ENTER_TENANT_ID",
        redirectUri: "/redirect", // set to a blank page for handling auth code response via popups
    },
    cache: {
        cacheLocation: "localStorage", // set your cache location to local storage
    },
});

window.onload = () => {
    
    const urlParams = new URLSearchParams(window.location.search);
    const sid = urlParams.get("sid");

    // attempt SSO
    myMSALObj.ssoSilent({
        sid: sid
    }).then((response) => {
        // do something with response
    }).catch(error => {
        // handle errors
    });
}
  • Api postMessage() можно использовать в родительском приложении и прослушивать события сообщений в дочернем приложении:
// Create the main myMSALObj instance
// configuration parameters are located at authConfig.js
const myMSALObj = new msal.PublicClientApplication({
    auth: {
        clientId: "ENTER_CLIENT_ID",
        authority: "https://login.microsoftonline.com/ENTER_TENANT_ID",
        redirectUri: "/redirect", // set to a blank page for handling auth code response via popups
    },
    cache: {
        cacheLocation: "localStorage", // set your cache location to local storage
    },
});

const parentDomain = "http://localhost:3001";

window.addEventListener("message", (event) => {
    // check the origin of the data
    if (event.origin === parentDomain) {
        const sid = event.data;

        // attempt SSO
        myMSALObj.ssoSilent({
            sid: sid
        }).then((response) => {
            // do something with response
        }).catch(error => {
            // handle errors
        });
    }
});

Обработка ошибок

Если произойдет сбой ssoSilent(), следует перехватывать и обрабатывать все ошибки. В частности:

  • InteractionRequiredError: будет возникать, если требуется согласие, пользователь должен выполнять многофакторную проверку подлинности и т. д. Эта ошибка часто может обрабатываться путем простого инициирования интерактивного API.
  • BrowserAuthError: будет возникать, если не указана или недопустимая подсказка учетной записи , всплывающие окна блокируются и т. д. Вам потребуется проверить errorCode и обработать их соответствующим образом.
    myMSALObj.ssoSilent({
        sid: sid
    }).then((response) => {
            // do something with response
        }).catch(error => {
            if (error instanceof msal.InteractionRequiredAuthError) {
                myMSALObj.loginPopup()
                    .then((response) => {
                        // do something with response
                    });
            } else if (error instanceof msal.BrowserAuthError) {
                if (error.errorCode === "silent_sso_error") {
                    // e.g. username is null
                }
                if (error.errorCode === "popup_window_error") {
                    // e.g. popups are blocked
                }
            } else {
                console.log(error);
            }
        });

Взаимодействие с пользователем

Если вы хотите свести к минимуму связь с idP, требующей взаимодействия с пользователем, или если у вас возникли проблемы с всплывающими окнами по какой-либо причине, можно рассмотреть следующие варианты:

Единый выход из системы

Вы можете использовать MSAL.js с URI выхода внешнего канала для достижения эффекта единого выхода между iframed и родительскими приложениями. Например, если вы хотите, чтобы пользователи автоматически выходили из приложений, встроенных через iframe, когда они выходят из основного приложения, необходимо включить выход через фронт-канал для приложений, встроенных через iframe. Для этого см.: Как настроить URI выхода через front-channel.