Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Antes de empezar aquí, asegúrese de comprender cómo inicializar el objeto de aplicación.
@azure/msal-angular usa el sistema de eventos expuesto por @azure/msal-browser, que emite eventos relacionados con la autenticación y MSAL, y se puede usar para actualizar la interfaz de usuario, mostrando mensajes de error, etc.
Consumo de eventos en tu aplicación
Los eventos de @azure/msal-angular son gestionados por el MsalBroadcastService y están disponibles al suscribirse al observable msalSubject$ en el MsalBroadcastService.
Este es un ejemplo de cómo puede consumir los eventos emitidos en la aplicación:
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();
}
}
Tenga en cuenta que es posible que tenga que convertir result.payload a un tipo específico para evitar errores de compilación. El tipo de carga dependerá del evento y se puede encontrar en nuestra documentación aquí.
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);
});
}
Para obtener el ejemplo completo de uso de eventos, consulte nuestro ejemplo aquí.
Tabla de eventos
Para obtener más información sobre el EventMessage objeto, incluida la tabla completa de eventos emitidos actualmente por @azure/msal-browser (incluidas las descripciones y las cargas relacionadas), consulte la documentación aquí.
Manejo de errores con eventos
Como EventError en EventMessage se define como AuthError | Error | null, se debe validar que un error sea del tipo correcto antes de acceder a propiedades específicas en este.
Consulta el ejemplo siguiente sobre cómo se puede convertir un error a AuthError para evitar errores de 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();
}
}
También se puede encontrar un ejemplo de control de errores en nuestro ejemplo de MSAL Angular B2C.
Sincronización del estado de inicio de sesión entre pestañas y ventanas
Si quiere actualizar la interfaz de usuario cuando un usuario inicia sesión o sale de la aplicación en otra pestaña o ventana, puede suscribirse a los ACCOUNT_ADDED eventos y ACCOUNT_REMOVED . La carga será el AccountInfo objeto que se agregó o quitó.
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();
}
}
También se puede encontrar un ejemplo completo en nuestros ejemplos.
El observable inProgress$
El observable inProgress$ también es gestionado por MsalBroadcastService, y se debe suscribir a él cuando la aplicación necesite conocer el estado de las interacciones, en particular para comprobar que las interacciones se han completado. Se recomienda comprobar que el estado de las interacciones es InteractionStatus.None anterior a las funciones que implican cuentas de usuario.
Ten en cuenta que el último InteractionStatus o el más reciente también estará disponible al suscribirte al observable inProgress$.
Consulte el ejemplo siguiente para su uso. También se puede encontrar un ejemplo completo en nuestros ejemplos. Puede encontrar una lista completa de los estados de interacción aquí.
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();
}
}
Configuraciones opcionales MsalBroadcastService
El MsalBroadcastService se puede configurar opcionalmente para reproducir eventos pasados al suscribirse a él. De forma predeterminada, están disponibles los eventos que se emiten después de suscribirse a MsalBroadcastService. Puede haber instancias en las que se necesiten eventos antes de la suscripción. Al proporcionar una configuración para MsalBroadcastService y establecer el parámetro eventsToReplay en un número, ese número de eventos anteriores estará disponible al suscribirse.
Para obtener más información sobre la reproducción de eventos, consulte los documentos de RxJS en ReplaySubjects aquí.
MsalBroadcastService se puede configurar en el archivo app.module.ts de la siguiente manera:
// 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 {}