Använda omdirigeringar i MSAL Angular

När du använder omdirigeringar med MSAL är det obligatoriskt att hantera omdirigeringar med antingen MsalRedirectComponent eller handleRedirectObservable.

Observera att specifik vägledning har lagts till för användning av MSAL Angular med fristående Angular-komponenter nedan.

  1. MsalRedirectComponent
  2. Prenumerera handleRedirectObservable manuellt
  3. Omdirigeringar med fristående komponenter

1. MsalRedirectComponent: En dedikerad handleRedirectObservable komponent

Note

Den här metoden är inte kompatibel med fristående Komponenter i Angular. Mer information finns i avsnittet om omdirigeringar med fristående komponenter nedan .

Det här är vår rekommenderade metod för att hantera omdirigeringar:

  • @azure/msal-angular tillhandahåller en dedikerad omdirigeringskomponent som kan importeras till ditt program. Vi rekommenderar att du importerar MsalRedirectComponent och startar detta tillsammans med AppComponent i ditt program på app.module.ts, eftersom detta hanterar alla omdirigeringar utan att dina komponenter behöver prenumerera handleRedirectObservable() manuellt.
  • Sidor som vill utföra funktioner efter omdirigeringar (t.ex. användarkontofunktioner, ändringar i användargränssnittet osv.) bör prenumerera på den observerbara filtreringen inProgress$ för InteractionStatus.None. Detta säkerställer att det inte pågår några interaktioner när du utför funktionerna. Observera att den sista/senaste InteractionStatus också kommer att vara tillgänglig när du prenumererar på inProgress$-observable. Mer information om hur du söker efter interaktioner finns i vår dokumentation om händelser .
  • Om du inte vill använda MsalRedirectComponentmåste du hantera omdirigeringar med handleRedirectObservable() dig själv, enligt beskrivningen i metoden nedan.
  • Se vårt Exempel på Angular-moduler för ett exempel på den här metoden.

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. Manuell prenumeration på handleRedirectObservable

Det här är inte vår rekommenderade metod, men om du inte kan bootstrap MsalRedirectComponentmåste du hantera omdirigeringar med hjälp av handleRedirectObservable följande:

  • handleRedirectObservable() bör prenumereras på på alla sidor som en omdirigering kan gå till. Sidor som skyddas av MSAL Guard behöver inte prenumerera på handleRedirectObservable(), eftersom omdirigeringar bearbetas i Guard.
  • Att få åtkomst till eller utföra någon åtgärd som rör användarkonton bör inte göras förrän handleRedirectObservable() är slutfört, eftersom det kanske inte är fullständigt ifyllt innan dess. Om interaktiva API:er dessutom anropas medan handleRedirectObservables() pågår resulterar det i ett interaction_in_progress-fel. Se vårt dokument om händelser för mer information om att kontrollera interaktioner, och vårt dokument om fel för information om felet interaction_in_progress.
  • Exempel på den här metoden finns i vårt MSAL Angular-modulexempel .

Exempel på home.component.ts fil:

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 Alternativ

handleRedirectObservable accepterar ett valfritt HandleRedirectPromiseOptions objekt med följande egenskaper:

Property Type Description
hash string Valfri hash som ska bearbetas i stället för den aktuella URL-hashen.
navigateToLoginRequestUrl boolean Om du vill navigera till den ursprungliga begärande-URL:en efter att omdirigeringen har bearbetats. Standardinställningen är true. Ange till false om du vill hantera navigeringen själv.

Exempel på användning:

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

Att skicka en hash-sträng direkt till handleRedirectObservable(hash) är inaktuell. Använd alternativobjektet i stället: handleRedirectObservable({ hash: "#..." }).

3. Omdirigeringar med fristående komponenter

Eftersom många Angular-applikationer som använder fristående komponenter inte kan starta upp MsalRedirectComponent måste man prenumerera direkt på handleRedirectObservable. Vår rekommendation är att prenumerera på den i app.component.ts filen.

  • Beroende på din programarkitektur kan du också behöva prenumerera på handleRedirectObservable() på andra områden.
  • Kontroll av pågående interaktioner gäller fortfarande. Mer information om hur du söker efter interaktioner finns i vårt dokument om händelser .
  • Exempel på den här metoden finns i vårt fristående Angular-exempel .

Exempel på app.component.ts fil:

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