Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Prima di iniziare, assicurarsi di comprendere come inizializzare l'oggetto applicazione.
@azure/msal-angular usa il sistema eventi esposto da @azure/msal-browser, che genera eventi correlati all'autenticazione e MSAL e può essere usato per l'aggiornamento dell'interfaccia utente, la visualizzazione dei messaggi di errore e così via.
Gestione degli eventi nell'app
Gli eventi in @azure/msal-angular vengono gestiti dal MsalBroadcastService e sono disponibili sottoscrivendosi all'osservabile msalSubject$ nel MsalBroadcastService.
Di seguito è riportato un esempio di come usare gli eventi generati nell'applicazione:
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();
}
}
Si noti che potrebbe essere necessario fare il cast di result.payload a un tipo specifico per evitare errori di compilazione. Il tipo di payload dipenderà dall'evento ed è disponibile nella documentazione qui.
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);
});
}
Per l'esempio completo dell'uso degli eventi, vedere l'esempio qui.
Tabella degli eventi
Per altre informazioni sull'oggetto EventMessage , inclusa la tabella completa degli eventi attualmente generati da @azure/msal-browser (incluse le descrizioni e i payload correlati), vedere la documentazione qui.
Gestione degli errori con gli eventi
Poiché l'elemento EventError in EventMessage è definito come AuthError | Error | null, è necessario verificare che un errore sia del tipo corretto prima di accedere alle sue proprietà specifiche.
Vedi l'esempio seguente di come convertire un errore in AuthError per evitare errori di 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();
}
}
Un esempio di gestione degli errori è disponibile anche nell'esempio MSAL Angular B2C.
Sincronizzazione dello stato di accesso tra schede e finestre
Se vuoi aggiornare l'interfaccia utente quando un utente effettua l'accesso o si disconnette dalla tua app in un'altra scheda o finestra, puoi iscriverti agli eventi ACCOUNT_ADDED e ACCOUNT_REMOVED. Il payload sarà l'oggetto AccountInfo aggiunto o rimosso.
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();
}
}
Un esempio completo è disponibile anche negli esempi.
L'osservabile inProgress$
L'osservabile inProgress$ viene gestito anche da MsalBroadcastServicee deve essere sottoscritto quando l'applicazione deve conoscere lo stato delle interazioni, in particolare per verificare che le interazioni siano completate. È consigliabile verificare che lo stato delle interazioni sia InteractionStatus.None prima delle funzioni che coinvolgono gli account utente.
Si noti che l'ultimo/più recente InteractionStatus sarà disponibile anche quando si sottoscrive l'osservabile inProgress$ .
Vedere l'esempio seguente per il relativo uso. Un esempio completo è disponibile anche negli esempi. Un elenco completo degli stati di interazione è disponibile qui.
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();
}
}
Configurazioni facoltative MsalBroadcastService
Il MsalBroadcastService può essere configurato facoltativamente per riprodurre eventi passati al momento della sottoscrizione. Per impostazione predefinita, sono disponibili gli eventi generati dopo la sottoscrizione a MsalBroadcastService. Potrebbero essere presenti istanze in cui sono necessari eventi prima della sottoscrizione. Fornendo una configurazione per MsalBroadcastService e impostando il eventsToReplay parametro su un numero, tale numero di eventi precedenti sarà disponibile nella sottoscrizione.
Per altre informazioni sulla riproduzione degli eventi, vedere la documentazione di RxJS su ReplaySubjects qui.
MsalBroadcastService può essere configurato nel file app.module.ts come segue:
// 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 {}