Použití přesměrování v MSAL Angular

Při použití přesměrování s MSAL je povinné zpracovávat přesměrování pomocí MsalRedirectComponent nebo handleRedirectObservable.

Všimněte si, že byly přidány konkrétní pokyny pro použití MSAL Angular se samostatnými komponentami Angular níže.

  1. MsalRedirectComponent
  2. Přihlášení k odběru handleRedirectObservable ručně
  3. Přesměrování se samostatnými komponentami

1. MsalRedirectComponent: Samostatná handleRedirectObservable komponenta

Note

Tento přístup není kompatibilní se samostatnými komponentami Angular. Další pokyny najdete v části o přesměrováních se samostatnými komponentami níže .

Toto je náš doporučený přístup pro zpracování přesměrování:

  • @azure/msal-angular poskytuje vyhrazenou komponentu pro přesměrování, kterou je možné importovat do aplikace. Doporučujeme importovat MsalRedirectComponent a inicializovat ji ve vaší aplikaci společně s AppComponent na platformě app.module.ts, protože tím bude zajištěno zpracování všech přesměrování, aniž by se vaše komponenty musely ručně přihlašovat k odběru handleRedirectObservable().
  • Stránky, které chtějí po přesměrování provádět určité operace (např. funkce uživatelského účtu, změny uživatelského rozhraní apod.), by se měly přihlásit k observable inProgress$ a filtrovat na InteractionStatus.None. Tím zajistíte, že při provádění funkcí neprobíhá žádná interakce. Všimněte si, že poslední / nejnovější InteractionStatus bude také k dispozici při přihlášení k inProgress$ observable. Další informace o kontrole interakcí najdete v naší dokumentaci k událostem .
  • Pokud nechcete používat MsalRedirectComponent, musíte přesměrování řešit sami pomocí handleRedirectObservable(), jak je popsáno níže.
  • Podívejte se na naši ukázku modulů Angular jako příklad tohoto přístupu.

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. Ruční přihlášení k odběru handleRedirectObservable

Toto není náš doporučený přístup, ale pokud nemůžete spustit metodu MsalRedirectComponent, musíte zpracovat přesměrování pomocí handleRedirectObservable následujícího postupu:

  • handleRedirectObservable() je třeba přihlásit k odběru na každé stránce, na niž může dojít k přesměrování. Stránky chráněné nástrojem MSAL Guard se nemusí přihlašovat k odběru handleRedirectObservable(), protože přesměrování jsou zpracovávána v mechanismu Guard.
  • Přístup k uživatelským účtům nebo provádění jakékoli akce související s uživatelskými účty by se neměl provádět, dokud handleRedirectObservable() se nedokončí, protože se do té doby nemusí plně vyplnit. Kromě toho platí, že pokud jsou během probíhání handleRedirectObservables() volána interaktivní rozhraní API, dojde k chybě interaction_in_progress. Další informace o kontrole interakcí a podrobnosti o chybách najdete v dokumentu o interaction_in_progress.
  • Podívejte se na naši ukázku modulů MSAL Angular s příklady tohoto přístupu.

Příklad souboru 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)
    });
  }

}

handleRedirectObservable možnosti

handleRedirectObservable přijímá volitelný HandleRedirectPromiseOptions objekt s následujícími vlastnostmi:

Property Typ Description
hash string Volitelný hash, který se má zpracovat místo aktuálního hashe adresy URL.
navigateToLoginRequestUrl boolean Určuje, jestli se má po zpracování přesměrování přejít na původní adresu URL požadavku. Výchozí hodnota je true. Nastavte na false, pokud chcete navigaci obsluhovat sami.

Příklady použití:

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

Přímé předávání řetězce hashe do handleRedirectObservable(hash) je zastaralé. Místo toho použijte objekt možností: handleRedirectObservable({ hash: "#..." }).

3. Přesměrování se samostatnými komponentami

Protože mnoho aplikací Angular využívajících samostatné komponenty nemůže spustit MsalRedirectComponent, handleRedirectObservable musí se přihlásit k odběru přímo. Doporučujeme přihlásit se k němu v souboru app.component.ts.

  • V závislosti na architektuře aplikace se možná budete muset přihlásit k odběru handleRedirectObservable() i v jiných oblastech.
  • Kontrola probíhajících interakcí stále platí. Další informace o kontrole interakcí najdete v našem dokumentu o událostech .
  • Příklady tohoto přístupu najdete v naší samostatné ukázce Angular .

app.component.ts Příklad souboru:

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