MSAL Angular でのリダイレクトの使用

MSAL でリダイレクトを使用する場合は、またはMsalRedirectComponentでリダイレクトを処理するhandleRedirectObservable

以下の Angular スタンドアロン コンポーネントで MSAL Angular を使用するための具体的なガイダンスが追加されていることに注意してください。

  1. MsalRedirectComponent
  2. handleRedirectObservableを手動で購読
  3. スタンドアロン コンポーネントを使用したリダイレクト

1. MsalRedirectComponent: 専用の handleRedirectObservable コンポーネント

Note

この方法は、Angular スタンドアロン コンポーネントと互換性がありません。 詳細なガイダンスについては、 以下のスタンドアロン コンポーネントでのリダイレクト に関するセクションを参照してください。

これは、リダイレクトを処理するための推奨されるアプローチです。

  • @azure/msal-angular には、アプリケーションにインポートできる専用のリダイレクト コンポーネントが用意されています。 MsalRedirectComponentをインポートし、これをアプリケーションのAppComponentと共にapp.module.tsにブートストラップすることをお勧めします。これは、コンポーネントが手動でhandleRedirectObservable()サブスクライブしなくてもすべてのリダイレクトを処理するためです。
  • リダイレクト後に機能 (ユーザー アカウント機能、UI の変更など) を実行したいページは、InteractionStatus.None でフィルターした inProgress$ Observable をサブスクライブする必要があります。 これにより、関数の実行時に進行中の相互作用が発生しないようにします。 最後の、つまり最新の InteractionStatus も、inProgress$ Observable をサブスクライブした際に利用できることに注意してください。 相互作用のチェックの詳細については、 イベント に関するドキュメントを参照してください。
  • MsalRedirectComponentを使用しない場合は、以下の方法で説明するとおり、handleRedirectObservable()を使ってリダイレクトを必ず自分で処理する必要があります。
  • このアプローチの例については 、Angular モジュールのサンプル を参照してください。

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 を手動で購読する

これは推奨される方法ではありませんが、MsalRedirectComponentをブートストラップできない場合は、次のようにを使用してリダイレクトを処理handleRedirectObservable

  • handleRedirectObservable() は、リダイレクトが発生する可能性のある すべての ページでサブスクライブする必要があります。 MSAL Guard によって保護されたページでは、リダイレクトは MSAL Guard で処理されるため、handleRedirectObservable() を購読する必要はありません。
  • ユーザー アカウントに関連するアクションへのアクセスまたは実行は、 handleRedirectObservable() が完了するまで実行しないでください。それまでは完全に設定されない可能性があるためです。 さらに、 handleRedirectObservables() の進行中に対話型 API が呼び出されると、 interaction_in_progress エラーが発生します。 相互作用のチェックの詳細についてはイベントに関するドキュメント、 エラーの詳細についてはinteraction_in_progressに関するドキュメントを参照してください。
  • このアプローチの例については 、MSAL Angular モジュールのサンプル を参照してください。

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 のオプション

handleRedirectObservable は、次のプロパティを持つ省略可能な HandleRedirectPromiseOptions オブジェクトを受け取ります。

財産 タイプ 説明
hash string 現在の URL ハッシュの代わりに処理する省略可能なハッシュ。
navigateToLoginRequestUrl boolean リダイレクトの処理後に元の要求 URL に移動するかどうかを指定します。 既定値は true です。 自分でナビゲーションを処理する場合は、 false に設定します。

使用例:

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

ハッシュ文字列を handleRedirectObservable(hash) に直接渡すことは非推奨です。 代わりに options オブジェクトを使用します: handleRedirectObservable({ hash: "#..." })

3. スタンドアロン コンポーネントを使用したリダイレクト

スタンドアロン コンポーネントを使用する Angular アプリケーションの多くは MsalRedirectComponentをブートストラップできないため、 handleRedirectObservable 直接サブスクライブする必要があります。 app.component.ts ファイルでサブスクライブすることをお勧めします。

  • アプリケーション アーキテクチャによっては、他の領域でも handleRedirectObservable() をサブスクライブする必要があります。
  • 進行中の相互作用の確認は引き続き適用されます。相互作用のチェックの詳細については、 イベント に関するドキュメントを参照してください。
  • このアプローチの例については、 Angular スタンドアロン サンプルを参照してください。

app.component.ts ファイルの例:

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