Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Перед началом работы убедитесь, что вы узнаете, как инициализировать объект приложения.
API входа в MSAL получают authorization code, который можно обменять на ID-токен для вошедшего в систему пользователя, при одновременном предоставлении согласия на области для дополнительного ресурса, а также на токен доступа, содержащий области, на которые пользователь дал согласие, чтобы приложение могло безопасно вызывать API.
Выбор типа взаимодействия
См. здесь , если вы не уверены в различиях между loginRedirect и loginPopup.
Вход пользователя
Необходимо передать объект запроса в API входа. Этот объект позволяет использовать различные параметры в запросе. Дополнительные сведения о параметрах объекта запроса см. здесь .
Для запросов входа все параметры являются необязательными, поэтому можно просто отправить пустой объект.
- Popup
try {
const loginResponse = await msalInstance.loginPopup({});
} catch (err) {
// handle error
}
- Перенаправить
try {
msalInstance.loginRedirect({});
} catch (err) {
// handle error
}
Или можно отправить набор областей доступа, на которые можно заранее дать согласие:
- Popup
var loginRequest = {
scopes: ["user.read", "mail.send"] // optional Array<string>
};
try {
const loginResponse = await msalInstance.loginPopup(loginRequest);
} catch (err) {
// handle error
}
- Перенаправить
var loginRequest = {
scopes: ["user.read", "mail.send"] // optional Array<string>
};
try {
msalInstance.loginRedirect(loginRequest);
} catch (err) {
// handle error
}
API учетной записи
После успешного выполнения вызова входа в систему можно использовать функцию getAllAccounts() для получения информации о пользователях, которые в данный момент вошли в систему.
const myAccounts: AccountInfo[] = msalInstance.getAllAccounts();
Если вы знаете сведения об учетной записи, вы также можете получить сведения об учетной записи с помощью getAccount() API:
const username = "test@contoso.com";
const myAccount: AccountInfo = msalInstance.getAccount({ username });
const homeAccountId = "userid.hometenantid"; // Best to retrieve the homeAccountId from an account object previously obtained through msal
const myAccount: AccountInfo = msalInstance.getAccount({ homeAccountId });
Note
Фильтрация по username предусмотрена для удобства и ее следует считать менее надежной, чем поиск на основе homeAccountId. По возможности используйте homeAccountId.
В сценариях B2C необходимо настроить арендатор B2C так, чтобы он возвращал утверждение emails в idTokens, чтобы можно было использовать фильтр username в API getAccount().
Эти API возвращают объект учетной записи или массив объектов учетной записи со следующей подписью:
{
// home account identifier for this account object
homeAccountId: string;
// Entity who issued the token represented as a full host of it (e.g. login.microsoftonline.com)
environment: string;
// Full tenant or organizational id that this account belongs to
tenantId: string;
// preferred_username claim of the id_token that represents this account.
username: string;
};
Тихий вход с помощью ssoSilent()
Если у вас уже есть активный сеанс на сервере аутентификации, вы можете использовать API ssoSilent() для запроса токенов без взаимодействия с пользователем.
С указанием пользователя
Если у вас уже есть сведения о входе пользователя, его можно передать в API, чтобы повысить производительность и убедиться, что сервер авторизации будет искать правильный сеанс учетной записи. Чтобы успешно получить токен без вывода запроса пользователю, можно передать в объекте запроса один из следующих элементов.
Рекомендуется использовать login_hint необязательное утверждение ID-токена (предоставляемое ssoSilent в виде loginHint), так как это наиболее надежное указание на учетную запись для запросов без вывода интерфейса (и интерактивных запросов).
-
account(которые можно получить с помощью одного из API учетной записи) -
sid(которое можно получить изidTokenClaimsобъектаaccount) -
login_hint(можно получить одним из следующих способов)- В качестве свойства
loginHintобъекта учетной записи (рекомендуется) - В качестве утверждения в токене идентификации для объекта учетной записи
login_hint(рекомендуется) - В качестве свойства
usernameобъекта учетной записи (не рекомендуется) - Как утверждение токена идентификации
upnобъекта учетной записи (не рекомендуется)
- В качестве свойства
Note
Свойства username и upn частично поддерживаются вместо фактического утверждения login_hint, однако использовать их не рекомендуется. Используйте свойства учетной записи loginHint или idTokenClaims.login_hint, если они доступны.
При передаче учетной записи выполняется поиск необязательного утверждения токена идентификации login_hint (предпочтительно), затем необязательного утверждения токена идентификации sid, после чего используется loginHint (если указано) или имя пользователя учетной записи.
const account = msalInstance.getAllAccounts()[0];
const silentRequest = {
scopes: ["User.Read", "Mail.Read"],
loginHint: account.loginHint, // alternatively, account.idTokenClaims.login_hint
};
try {
const loginResponse = await msalInstance.ssoSilent(silentRequest);
} catch (err) {
if (err instanceof InteractionRequiredAuthError) {
const loginResponse = await msalInstance.loginPopup(silentRequest).catch(error => {
// handle error
});
} else {
// handle error
}
}
Без указания пользователя
Если о пользователе доступно недостаточно информации, вы можете попробовать использовать API ssoSilentбез передачи account, sid или login_hint.
const silentRequest = {
scopes: ["User.Read", "Mail.Read"]
};
Однако имейте в виду, что если в вашем приложении есть разные ветви кода для нескольких пользователей в рамках одного сеанса браузера или если у пользователя есть несколько учетных записей в рамках этого же сеанса браузера, то вероятность ошибок при тихом входе выше. В случае нескольких сеансов учетной записи, обнаруженных сервером авторизации, может появилась следующая ошибка:
InteractionRequiredAuthError: interaction_required: AADSTS16000: Either multiple user identities are available for the current request or selected account is not supported for the scenario.
Это означает, что сервер не мог определить учетную запись для входа, и потребуется один из указанных выше параметров (account, login_hint, sid) или интерактивный вход для выбора учетной записи.
Предупреждение
При использовании ssoSilent служба пытается загрузить страницу по URI перенаправления в невидимом встроенном iframe. Политики безопасности содержимого и значения заголовков HTTP, присутствующих в ответе на страницу перенаправления приложения URI, такие как X-FRAME-OPTIONS: DENY и X-FRAME-OPTIONS: SAMEORIGIN, могут предотвратить загрузку приложения в iframe, эффективно блокируя автоматический единый вход. Если вы планируете использовать ssoSilent, убедитесь, что URI перенаправления указывает на страницу, которая не реализует такие политики.
Рекомендации по перенаправлению URI
Теперь для всех потоков проверки подлинности требуется выделенная страница перенаправления , реализующая мост перенаправления MSAL. Это необходимо для поддержки заголовков COOP (Cross-Origin-Opener-Policy) и обеспечения безопасного взаимодействия между всплывающими окнами, iframe и основным приложением.
Настройка страницы перенаправления
Ваш redirectUri должен указывать на отдельную страницу, которая загружает скрипт моста перенаправления. Эта страница должна:
- Загрузка скрипта моста перенаправления — этот скрипт обрабатывает взаимодействие с основным окном.
- Не включать никакой JavaScript, кроме bridge-скрипта — на странице перенаправления должен выполняться только bridge-скрипт
- Не включать логику маршрутизации . Избегайте библиотек маршрутизаторов, которые могут препятствовать обработке хэша
- Быть зарегистрированным в разделе регистрации приложения — URI должен в точности соответствовать тому, что зарегистрировано на портале Azure
Пример страницы перенаправления (при использовании пакета, например Vite или Webpack):
<!DOCTYPE html>
<html>
<head>
<title>Redirect</title>
</head>
<body>
<p>Processing authentication...</p>
<script type="module">
import { broadcastResponseToMainFrame } from "@azure/msal-browser/redirect-bridge";
broadcastResponseToMainFrame();
</script>
</body>
</html>
Note
Описатель @azure/msal-browser/redirect-bridge должен быть разрешен пакетом (Vite, Webpack и т. д.) — это не URL-адрес, который браузеры могут получить напрямую. Инструкции для конкретной платформы см. в руководстве по настройке моста перенаправления.
Configuration
Вы можете задать redirectUri глобально в конфигурации MSAL или для каждого запроса отдельно:
Глобальная конфигурация:
const msalConfig = {
auth: {
clientId: "your-client-id",
authority: "https://login.microsoftonline.com/common",
redirectUri: "http://localhost:3000/redirect"
}
};
const msalInstance = new PublicClientApplication(msalConfig);
Конфигурация каждого запроса:
msalInstance.loginPopup({
scopes: ["user.read"],
redirectUri: "http://localhost:3000/redirect"
});
Дополнительные сведения и полные примеры реализаций см. в следующей статье:
Обработка ошибок всплывающих окон interaction_in_progress
Для всплывающих потоков можно использовать overrideInteractionInProgress флаг для отмены ожидающего взаимодействия и запуска нового. Это полезно для сценариев восстановления, когда пользователь закрыл всплывающее окно или произошёл сбой взаимодействия.
Note
Эта функция доступна только для всплывающих потоков и не поддерживается для потоков перенаправления. При использовании заголовка COOP (Cross-Origin-Opener-Policy) традиционная window.opener связь разрывается, что позволяет всплывающим окнам взаимодействовать с основным фреймом только через BroadcastChannel.
Important
Установка этого параметра true принудительно отменит любой ожидающий запрос проверки подлинности всплывающего окна, но не закроет открытые всплывающие окна.
Если задано значение true:
- Если в настоящее время выполняется другое всплывающее взаимодействие, оно принудительно отменено, но все открытые всплывающие окна не закрываются
- Незавершённое взаимодействие завершается с ошибкой
interaction_in_progress_cancelled - Новый сценарий всплывающего окна запускается сразу
Допустимые варианты использования:
- Восстановление после ошибок, когда пользователь отменил всплывающее окно (всплывающее окно было закрыто без завершения проверки подлинности)
- Реализация настраиваемых сценариев восстановления после ошибок
- Обеспечение механизма повторной попытки после неудачного взаимодействия со всплывающим окном
По умолчанию:false
Важно: Используйте только при нажатии кнопки
Не повторяйте автоматически при перехвате ошибки interaction_in_progress. Переопределение должно активироваться только явным действием пользователя (например, нажатием кнопки "Повторить"). Автоматическое переопределение взаимодействий может привести к следующим последствиям:
- Условия гонки между несколькими потоками проверки подлинности
- Непредвиденные отмены допустимых попыток проверки подлинности
- Плохое взаимодействие с пользователями при запуске и остановке потоков проверки подлинности неожиданно
- Открыто много всплывающих окон, которые не приводят к успешным ответам аутентификации
Пример: Корректная обработка ошибок с повторной попыткой, инициированной пользователем
Полные примеры реализации с визуальной обратной связью см.:
- Пример Express — демонстрирует реализацию JavaScript с помощью пользовательского CSS
- Пример маршрутизатора React — демонстрирует реализацию React с компонентами Material-UI
Оба примера демонстрируют:
- Предупреждение, отображаемое во время проверки подлинности всплывающего окна
- Модальное окно/диалог повтора с четким объяснением при ошибке
interaction_in_progress - Корректное управление состоянием для повторной попытки, инициированной пользователем
- Компоненты пользовательского интерфейса, готовые к работе
// State to track if user wants to retry
let userWantsRetry = false;
// Button click handler
async function handleLoginClick() {
try {
const loginRequest = {
scopes: ["user.read"]
};
// If user explicitly clicked retry, override the existing interaction
if (userWantsRetry) {
loginRequest.overrideInteractionInProgress = true;
userWantsRetry = false; // Reset flag
}
const response = await msalInstance.loginPopup(loginRequest);
// Handle successful login
} catch (error) {
if (error.errorCode === 'interaction_in_progress') {
// Show retry button to user - DO NOT automatically retry
showRetryButton();
} else {
// Handle other errors
console.error(error);
}
}
}
// Retry button click handler
function handleRetryClick() {
userWantsRetry = true; // Set flag for next login attempt
handleLoginClick(); // User explicitly requested retry
}
Пример: компонент React с повторной попыткой, инициируемой пользователем
function LoginButton() {
const { instance } = useMsal();
const [showRetry, setShowRetry] = useState(false);
const [retryRequested, setRetryRequested] = useState(false);
const handleLogin = async () => {
try {
const loginRequest = {
scopes: ["user.read"],
// Only override if user clicked the retry button
overrideInteractionInProgress: retryRequested
};
setRetryRequested(false); // Reset retry flag
const response = await instance.loginPopup(loginRequest);
setShowRetry(false);
} catch (error) {
if (error.errorCode === 'interaction_in_progress') {
// Show retry button - let user decide whether to retry
setShowRetry(true);
} else {
console.error(error);
}
}
};
const handleRetry = () => {
setRetryRequested(true); // User explicitly requested retry
handleLogin();
};
return (
<div>
<button onClick={handleLogin}>Login</button>
{showRetry && (
<button onClick={handleRetry}>
Retry Login (Cancel Pending)
</button>
)}
</div>
);
}
Дальнейшие шаги
Узнайте, как получить и использовать маркер доступа!