Verwendung von Umleitungen in MSAL Angular

Bei der Verwendung von Umleitungen mit MSAL ist es zwingend erforderlich, Umleitungen entweder mit dem MsalRedirectComponent oder dem handleRedirectObservable zu verarbeiten.

Beachten Sie, dass unten spezifische Richtlinien für die Verwendung von MSAL Angular mit eigenständigen Angular-Komponenten hinzugefügt wurden.

  1. MsalRedirectComponent
  2. Manuelles Abonnieren von handleRedirectObservable
  3. Umleitungen mit eigenständigen Komponenten

1. MsalRedirectComponent: Eine dedizierte handleRedirectObservable Komponente

Note

Dieser Ansatz ist nicht mit eigenständigen Angular-Komponenten kompatibel. Weitere Anleitungen finden Sie im Abschnitt zu Umleitungen mit eigenständigen Komponenten unten .

Dies ist unser empfohlener Ansatz für die Behandlung von Umleitungen:

  • @azure/msal-angular stellt eine dedizierte Umleitungskomponente bereit, die in Ihre Anwendung importiert werden kann. Wir empfehlen, das MsalRedirectComponent zu importieren und dieses zusammen mit AppComponent in Ihrer Anwendung auf dem app.module.ts zu initialisieren, da dadurch alle Umleitungen verarbeitet werden, ohne dass Ihre Komponenten handleRedirectObservable() manuell abonnieren müssen.
  • Seiten, die nach Weiterleitungen Funktionen ausführen möchten (z. B. Benutzerkontofunktionen, UI-Änderungen usw.), sollten das Observable inProgress$ abonnieren und nach InteractionStatus.None filtern. Dadurch wird sichergestellt, dass beim Ausführen der Funktionen keine Interaktionen ausgeführt werden. Beachten Sie, dass die letzte / neueste InteractionStatus auch verfügbar ist, wenn Sie das inProgress$-Observable abonnieren. Weitere Informationen zur Überprüfung auf Interaktionen finden Sie in unserer Dokumentation zu Veranstaltungen .
  • Wenn Sie die MsalRedirectComponent nicht verwenden möchten, müssen Sie Umleitungen mit handleRedirectObservable() selbst behandeln, wie im nachstehenden Ansatz beschrieben.
  • Ein Beispiel für diesen Ansatz finden Sie in unserem Angular-Modulbeispiel .

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. handleRedirectObservable manuell abonnieren

Dies ist nicht unsere empfohlene Vorgehensweise, aber wenn Sie MsalRedirectComponent nicht initialisieren können, müssen Sie Weiterleitungen mithilfe des handleRedirectObservable wie folgt behandeln:

  • handleRedirectObservable() sollte auf jeder Seite abonniert werden, auf der eine Umleitung auftreten kann. Seiten, die von MSAL Guard geschützt sind, müssen nicht abonniert handleRedirectObservable()werden, da Umleitungen in der Guard verarbeitet werden.
  • Auf Benutzerkonten zuzugreifen oder entsprechende Aktionen auszuführen sollte nicht erfolgen, bevor handleRedirectObservable() abgeschlossen ist, da diese bis dahin möglicherweise nicht vollständig befüllt sind. Außerdem führt der Aufruf interaktiver APIs, während handleRedirectObservables() ausgeführt wird, zu einem interaction_in_progress-Fehler. Weitere Informationen zum Prüfen von Interaktionen finden Sie in unserem Dokument zu Ereignissen und Details zum interaction_in_progress-Fehler in unserem Dokument zu Fehlern.
  • Sehen Sie sich unser MSAL Angular-Module-Beispiel für Beispiele zu diesem Ansatz an.

Beispiel für home.component.ts Datei:

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)
    });
  }

}

handleRedirectObservable-Optionen

handleRedirectObservable akzeptiert ein optionales HandleRedirectPromiseOptions Objekt mit den folgenden Eigenschaften:

Eigentum Typ Description
hash string Optionaler Hash, der anstelle des aktuellen URL-Hash verarbeitet werden soll.
navigateToLoginRequestUrl boolean Gibt an, ob nach der Verarbeitung der Umleitung zur ursprünglichen Anforderungs-URL navigiert werden soll. Wird standardmäßig auf true festgelegt. Auf false festlegen, wenn Sie die Navigation selbst verwalten möchten.

Beispielverwendung:

// 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

Das direkte Übergeben einer Hashzeichenfolge an handleRedirectObservable(hash) ist veraltet. Verwenden Sie stattdessen das Optionsobjekt: handleRedirectObservable({ hash: "#..." }).

3. Umleitungen mit eigenständigen Komponenten

Da viele Angular-Anwendungen, die eigenständige Komponenten verwenden, MsalRedirectComponent nicht initialisieren können, muss handleRedirectObservable direkt abonniert werden. Unsere Empfehlung ist, sie in der app.component.ts Datei zu abonnieren.

  • Abhängig von Ihrer Anwendungsarchitektur müssen Sie handleRedirectObservable() möglicherweise auch in anderen Bereichen abonnieren.
  • Die Überprüfung auf laufende Interaktionen gilt weiterhin. Weitere Informationen zur Überprüfung auf Interaktionen finden Sie in unserem Dokument zu Ereignissen .
  • Beispiele für diesen Ansatz finden Sie in unserem eigenständigen Angular-Beispiel .

Beispiel für app.component.ts Datei:

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();
  }
}