Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Перед началом работы убедитесь, что вы узнаете, как инициализировать объект приложения.
@azure/msal-angular использует систему событий, предоставленную @azure/msal-browser, которая выдает события, связанные с проверкой подлинности и MSAL, и может использоваться для обновления пользовательского интерфейса, отображения сообщений об ошибках и т. д.
Обработка событий в вашем приложении
События в @azure/msal-angular управляются MsalBroadcastService и доступны при подписке на наблюдаемый объект msalSubject$ в MsalBroadcastService.
Вот пример того, как можно обрабатывать отправляемые события в вашем приложении:
import { MsalBroadcastService } from '@azure/msal-angular';
import { EventMessage, EventType } from '@azure/msal-browser';
export class AppComponent implements OnInit, OnDestroy {
private readonly _destroying$ = new Subject<void>();
constructor(
//...
private msalBroadcastService: MsalBroadcastService
) {}
ngOnInit(): void {
this.msalBroadcastService.msalSubject$
.pipe(
// Optional filtering of events.
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
takeUntil(this._destroying$)
)
.subscribe((result: EventMessage) => {
// Do something with the result
});
}
ngOnDestroy(): void {
this._destroying$.next(null);
this._destroying$.complete();
}
}
Обратите внимание, что для предотвращения ошибок компиляции может потребоваться приведение result.payload в качестве определенного типа. Тип полезной нагрузки будет зависеть от события, и его можно найти в нашей документации здесь.
ngOnInit(): void {
this.msalBroadcastService.msalSubject$
.pipe(
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
)
.subscribe((result: EventMessage) => {
// Casting payload as AuthenticationResult to access account
const payload = result.payload as AuthenticationResult;
this.authService.instance.setActiveAccount(payload.account);
});
}
Полный пример использования событий см. здесь.
Таблица событий
Дополнительные сведения об объекте EventMessage, включая полную таблицу событий, в настоящее время отправляемых @azure/msal-browser (включая описания и связанные данные полезной нагрузки), см. в документации здесь.
Обработка ошибок с помощью событий
Поскольку EventError в EventMessage определяется как AuthError | Error | null, перед обращением к её определённым свойствам следует проверить, что ошибка имеет правильный тип.
Ниже приведен пример того, как можно привести ошибку к типу AuthError, чтобы избежать ошибок TypeScript:
import { MsalBroadcastService } from '@azure/msal-angular';
import { EventMessage, EventType } from '@azure/msal-browser';
export class AppComponent implements OnInit, OnDestroy {
private readonly _destroying$ = new Subject<void>();
constructor(
//...
private msalBroadcastService: MsalBroadcastService
) {}
ngOnInit(): void {
this.msalBroadcastService.msalSubject$
.pipe(
// Optional filtering of events
filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_FAILURE),
takeUntil(this._destroying$)
)
.subscribe((result: EventMessage) => {
if (result.error instanceof AuthError) {
// Do something with the error
}
});
}
ngOnDestroy(): void {
this._destroying$.next(null);
this._destroying$.complete();
}
}
Пример обработки ошибок также можно найти в нашем примере MSAL Angular B2C.
Синхронизация состояния входа в систему между вкладками и окнами
Если вы хотите обновлять интерфейс, когда пользователь выполняет вход в приложение или выходит из учётной записи в другой вкладке или окне, вы можете подписаться на события ACCOUNT_ADDED и ACCOUNT_REMOVED. В качестве полезной нагрузки будет передан объект AccountInfo, который был добавлен или удалён.
import { MsalService, MsalBroadcastService } from '@azure/msal-angular';
import { EventMessage, EventType } from '@azure/msal-browser';
export class AppComponent implements OnInit, OnDestroy {
private readonly _destroying$ = new Subject<void>();
constructor(
//...
private authService: MsalService,
private msalBroadcastService: MsalBroadcastService
) {}
ngOnInit(): void {
this.authService.instance.enableAccountStorageEvents(); // Register the storage listener that will be emitting the events
this.msalBroadcastService.msalSubject$
.pipe(
// Optional filtering of events
filter((msg: EventMessage) => msg.eventType === EventType.ACCOUNT_ADDED || msg.eventType === EventType.ACCOUNT_REMOVED),
takeUntil(this._destroying$)
)
.subscribe((result: EventMessage) => {
if (this.authService.msalInstance.getAllAccounts().length === 0) {
// Account logged out in a different tab, redirect to homepage
window.location.pathname = "/";
} else {
// Update UI to show user is signed in. result.payload contains the account that was logged in
}
});
}
ngOnDestroy(): void {
this._destroying$.next(null);
this._destroying$.complete();
}
}
Полный пример также можно найти в наших примерах.
Наблюдаемое значение inProgress$
Наблюдаемый объект inProgress$ также обрабатывается с помощью MsalBroadcastService, и на него следует подписаться, когда приложению необходимо знать состояние взаимодействий, в частности, чтобы проверить, завершены ли взаимодействия. Рекомендуется InteractionStatus.None проверить состояние взаимодействия перед функциями, связанными с учетными записями пользователей.
Обратите внимание, что последний / самый недавний InteractionStatus будет также доступен при подписке на наблюдаемый объект inProgress$.
См. приведенный ниже пример для его использования. Полный пример также можно найти в наших примерах. Полный список состояний взаимодействия можно найти здесь.
import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
import { MsalBroadcastService} from '@azure/msal-angular';
import { InteractionStatus } from '@azure/msal-browser';
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
private readonly _destroying$ = new Subject<void>();
constructor(
private msalBroadcastService: MsalBroadcastService
) {}
ngOnInit(): void {
this.msalBroadcastService.inProgress$
.pipe(
// Filtering for all interactions to be completed
filter((status: InteractionStatus) => status === InteractionStatus.None),
takeUntil(this._destroying$)
)
.subscribe(() => {
// Do something related to user accounts or UI here
})
}
ngOnDestroy(): void {
this._destroying$.next(null);
this._destroying$.complete();
}
}
Необязательные MsalBroadcastService конфигурации
MsalBroadcastService при необходимости можно настроить так, чтобы при подписке на него он повторно воспроизводил прошлые события. По умолчанию доступны события, генерируемые после подписки на MsalBroadcastService. В некоторых случаях могут потребоваться события, предшествующие подписке. Если предоставить конфигурацию для MsalBroadcastService и установить параметру eventsToReplay числовое значение, то при подписке будет доступно соответствующее количество прошлых событий.
Дополнительные сведения о повторном отображении событий см. в документации RxJS по replaySubjects здесь.
MsalBroadcastService можно настроить в файле app.module.ts следующим образом:
// app.module.ts
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppComponent } from './app.component';
import { MsalModule, MsalService, MsalGuard, MsalInterceptor, MsalBroadcastService, MsalRedirectComponent, MSAL_BROADCAST_CONFIG } from "@azure/msal-angular"; // Import MsalBroadcastService and MSAL_BROADCAST_CONFIG here
import { PublicClientApplication, InteractionType, BrowserCacheLocation } from "@azure/msal-browser";
@NgModule({
imports: [
MsalModule.forRoot( new PublicClientApplication({ // MSAL Configuration
auth: {
clientId: "clientid",
authority: "https://login.microsoftonline.com/common/",
redirectUri: "http://localhost:4200/",
postLogoutRedirectUri: "http://localhost:4200/",
navigateToLoginRequestUrl: true
},
cache: {
cacheLocation : BrowserCacheLocation.LocalStorage,
},
system: {
loggerOptions: {
loggerCallback: () => {},
piiLoggingEnabled: false
}
}
}), {
interactionType: InteractionType.Popup, // MSAL Guard Configuration
authRequest: {
scopes: ['user.read']
},
loginFailedRoute: "/login-failed"
}, {
interactionType: InteractionType.Redirect, // MSAL Interceptor Configuration
protectedResourceMap
})
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true
},
{
provide: MSAL_BROADCAST_CONFIG, // Add configuration to providers here
useValue: {
eventsToReplay: 2 // Set how many events you want to replay when subscribing
}
},
MsalGuard,
MsalBroadcastService // Ensure the MsalBroadcastService is provided
],
bootstrap: [AppComponent, MsalRedirectComponent]
})
export class AppModule {}