Utilisation de redirections dans MSAL Angular

Lorsque vous utilisez des redirections avec MSAL, il est obligatoire de gérer les redirections avec le MsalRedirectComponent ou handleRedirectObservable.

Notez que des instructions spécifiques ont été ajoutées ci-dessous concernant l’utilisation de MSAL Angular avec les composants autonomes d’Angular.

  1. MsalRedirectComponent
  2. Abonnement à handleRedirectObservable manuellement
  3. Redirections avec des composants autonomes

1. MsalRedirectComponent: composant dédié handleRedirectObservable

Note

Cette approche n’est pas compatible avec les composants autonomes Angular. Consultez la section sur les redirections avec les composants autonomes ci-dessous pour obtenir des conseils supplémentaires.

Il s’agit de notre approche recommandée pour la gestion des redirections :

  • @azure/msal-angular fournit un composant de redirection dédié qui peut être importé dans votre application. Nous vous recommandons d’importer le MsalRedirectComponent et d’initialiser celui-ci aux côtés de AppComponent dans votre application au niveau de app.module.ts, car cela gérera toutes les redirections sans que vos composants n’aient besoin de s’abonner manuellement à handleRedirectObservable().
  • Les pages qui souhaitent exécuter certaines actions après des redirections (par exemple, des actions liées au compte utilisateur, des modifications de l’interface utilisateur, etc.) doivent s’abonner à l’observable inProgress$, en filtrant sur InteractionStatus.None. Cela garantit qu’aucune interaction n’est en cours lors de l’exécution des fonctions. Notez que le dernier /le plus récent InteractionStatus sera également disponible lors de l’abonnement à l’observable inProgress$ . Consultez notre documentation sur les événements pour plus d’informations sur la vérification des interactions.
  • Si vous ne souhaitez pas utiliser le MsalRedirectComponent, vous devez gérer les redirections avec handleRedirectObservable() vous-même, comme indiqué dans l’approche ci-dessous.
  • Consultez notre exemple de modules Angular pour obtenir un exemple de cette approche.

msal.redirect.component.ts

// This component is part of @azure/msal-angular and can be imported and bootstrapped
import { Component, OnInit } from "@angular/core";
import { MsalService } from "./msal.service.ts";

@Component({
  selector: 'app-redirect', // Selector to be added to index.html
  template: ''
})
export class MsalRedirectComponent implements OnInit {
  
  constructor(private authService: MsalService) { }
  
  ngOnInit(): void {    
      this.authService.handleRedirectObservable().subscribe();
  }
  
}

index.html

<body>
  <app-root></app-root>
  <app-redirect></app-redirect> <!-- Selector for additional bootstrapped component -->
</body>

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';

import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatListModule } from '@angular/material/list';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';

import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { IPublicClientApplication, PublicClientApplication, InteractionType, BrowserCacheLocation, LogLevel } from '@azure/msal-browser';
import { MsalGuard, MsalInterceptor, MsalBroadcastService, MsalInterceptorConfiguration, MsalModule, MsalService, MSAL_GUARD_CONFIG, MSAL_INSTANCE, MSAL_INTERCEPTOR_CONFIG, MsalGuardConfiguration, MsalRedirectComponent } from '@azure/msal-angular'; // Redirect component imported from msal-angular

export function loggerCallback(logLevel: LogLevel, message: string) {
  console.log(message);
}

export function MSALInstanceFactory(): IPublicClientApplication {
  return new PublicClientApplication({
    auth: {
      clientId: '00001111-aaaa-2222-bbbb-3333cccc4444',
      redirectUri: 'http://localhost:4200',
      postLogoutRedirectUri: 'http://localhost:4200'
    },
    cache: {
      cacheLocation: BrowserCacheLocation.LocalStorage,
    },
    system: {
      loggerOptions: {
        loggerCallback,
        logLevel: LogLevel.Info,
        piiLoggingEnabled: false
      }
    }
  });
}

export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
  const protectedResourceMap = new Map<string, Array<string>>();
  protectedResourceMap.set('https://graph.microsoft.com/v1.0/me', ['user.read']);

  return {
    interactionType: InteractionType.Redirect,
    protectedResourceMap
  };
}

export function MSALGuardConfigFactory(): MsalGuardConfiguration {
  return { interactionType: InteractionType.Redirect };
}

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    ProfileComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    MatButtonModule,
    MatToolbarModule,
    MatListModule,
    HttpClientModule,
    MsalModule
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: MsalInterceptor,
      multi: true
    },
    {
      provide: MSAL_INSTANCE,
      useFactory: MSALInstanceFactory
    },
    {
      provide: MSAL_GUARD_CONFIG,
      useFactory: MSALGuardConfigFactory
    },
    {
      provide: MSAL_INTERCEPTOR_CONFIG,
      useFactory: MSALInterceptorConfigFactory
    },
    MsalService,
    MsalGuard,
    MsalBroadcastService
  ],
  bootstrap: [AppComponent, MsalRedirectComponent] // Redirect component bootstrapped here
})
export class AppModule { }

app.component.ts

import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
import { MsalBroadcastService, InteractionStatus } from '@azure/msal-angular';
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(
        filter((status: InteractionStatus) => status === InteractionStatus.None),
        takeUntil(this._destroying$)
      )
      .subscribe(() => {
        // Do user account/UI functions here
      })
  }

2. Abonnement à handleRedirectObservable manuellement

Ce n’est pas l’approche que nous recommandons, mais si vous ne parvenez pas à initialiser le MsalRedirectComponent, vous devez gérer les redirections à l’aide du handleRedirectObservable, comme suit :

  • handleRedirectObservable() doit être souscrit sur chaque page vers laquelle une redirection peut avoir lieu. Les pages protégées par la protection MSAL Guard n’ont pas besoin de s’abonner à handleRedirectObservable(), car les redirections sont traitées par la protection MSAL Guard.
  • Il ne faut pas accéder aux comptes d’utilisateur ni effectuer d’action les concernant tant que handleRedirectObservable() n’est pas terminé, car il se peut qu’il ne soit pas encore entièrement renseigné d’ici là. De plus, si des API interactives sont appelées alors que handleRedirectObservables() est en cours, cela entraînera une erreur interaction_in_progress. Consultez notre document sur les événements pour plus d’informations sur la vérification des interactions et notre document sur les erreurs pour plus d’informations sur l’erreur interaction_in_progress .
  • Consultez notre exemple de modules MSAL Angular pour obtenir des exemples de cette approche.

Exemple de fichier home.component.ts :

import { Component, OnInit } from '@angular/core';
import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
import { AuthenticationResult } from '@azure/msal-browser';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor(private authService: MsalService) { }

  ngOnInit(): void {
    this.authService.handleRedirectObservable().subscribe({
      next: (result: AuthenticationResult) => {
        // Perform actions related to user accounts here
      },
      error: (error) => console.log(error)
    });
  }

}

Options handleRedirectObservable

handleRedirectObservable accepte un objet facultatif HandleRedirectPromiseOptions avec les propriétés suivantes :

Propriété Type Description
hash string Hachage facultatif à traiter au lieu du hachage d’URL actuel.
navigateToLoginRequestUrl boolean Indique s’il faut accéder à l’URL de requête d’origine après avoir traité la redirection. La valeur par défaut est true. Définissez sur false si vous souhaitez gérer vous-même la navigation.

Exemple d’utilisation :

// Basic usage - processes redirect and navigates to original URL
this.authService.handleRedirectObservable().subscribe();

// Disable automatic navigation after redirect
this.authService.handleRedirectObservable({ navigateToLoginRequestUrl: false }).subscribe({
  next: (result: AuthenticationResult) => {
    if (result) {
      // Handle navigation yourself
      this.router.navigate(['/home']);
    }
  }
});

// Process a specific hash
this.authService.handleRedirectObservable({ hash: '#code=...' }).subscribe();

Note

Le passage d’une chaîne de hachage directement à handleRedirectObservable(hash) est déconseillé. Utilisez l’objet options à la place : handleRedirectObservable({ hash: "#..." }).

3. Redirige avec des composants autonomes

Comme de nombreuses applications Angular utilisant des composants autonomes ne peuvent pas amorcer MsalRedirectComponent, il faut souscrire directement à handleRedirectObservable. Nous vous recommandons de vous y inscrire dans le fichier app.component.ts.

  • Selon l’architecture de votre application, vous devrez peut-être également vous abonner à handleRedirectObservable() dans d’autres parties.
  • La vérification des interactions en cours s’applique toujours, consultez notre document sur les événements pour plus d’informations sur la vérification des interactions.
  • Consultez notre exemple autonome Angular pour obtenir des exemples de cette approche.

Exemple de app.component.ts fichier :

import { Component, OnInit, Inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    standalone: true,
    imports: [CommonModule, RouterModule]
})
export class AppComponent implements OnInit {

  constructor(
    @Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration,
    private authService: MsalService,
    private msalBroadcastService: MsalBroadcastService
  ) {}

  ngOnInit(): void {
    this.authService.handleRedirectObservable().subscribe();
  }
}