Freigeben über


Tutorial: Anmelden von Benutzern und Aufrufen der Microsoft Graph-API über eine Angular-Single-Page-Webanwendung (SPA) unter Verwendung des Autorisierungscodeflows

In diesem Tutorial erstellen Sie eine Angular Single-Page-Application (SPA), die Benutzende anmeldet und die Microsoft Graph-API aufruft, indem Sie den Autorisierungscodeflow mit PKCE (Proof Key for Code Exchange) verwenden. Die von Ihnen erstellte SPA verwendet die Microsoft-Authentifizierungsbibliothek (Microsoft Authentication Library, MSAL) für Angular v2.

Dieses Tutorial umfasst folgende Punkte:

  • Registrieren der Anwendung im Microsoft Entra Admin Center
  • Erstellen eines Angular-Projekts mit npm
  • Hinzufügen von Code zur Unterstützung der Benutzeranmeldung und -abmeldung
  • Hinzufügen von Code zum Aufrufen der Microsoft Graph-API
  • Testen der App

MSAL Angular v2 verwendet den Autorisierungscodeflow mit PKCE im Browser und verbessert damit MSAL Angular v1, das den impliziten Gewährungsflow verwendete. Es wird empfohlen, den Autorisierungscodeflow mit PKCE für Einzelseitenanwendungen (SPAs) zu verwenden, da er sicherer als der implizite Flow ist. Der implizite Flow wird von MSAL Angular v2 NICHT unterstützt.

Voraussetzungen

  • Node.js zum Ausführen eines lokalen Webservers
  • Visual Studio Code oder einen anderen Editor zum Bearbeiten von Projektdateien

Funktionsweise der Beispiel-App

Diagramm, das den Autorisierungscodefluss in einer Single-Page-Webanwendung darstellt.

Die in diesem Tutorial erstellte Beispiel-App ermöglicht einer Angular-SPA das Abfragen der Microsoft Graph-API oder einer Web-API, die von der Microsoft Identity Platform ausgegebene Token akzeptiert. Dabei wird die Microsoft Authentication Library (MSAL) für Angular v2 verwendet – ein Wrapper der MSAL.js v2-Bibliothek. Mit MSAL Angular können auf Angular 9+ basierende Anwendungen sowohl Unternehmensbenutzer über Microsoft Entra ID als auch Benutzer von Microsoft-Konten sowie Benutzer mit Social Media-Identität (z. B. Facebook, Google und LinkedIn) authentifizieren. Die Bibliothek ermöglicht es Anwendungen zudem, Zugriff auf Microsoft Cloud Services und Microsoft Graph zu erhalten.

In diesem Szenario wird nach der Benutzeranmeldung ein Zugriffstoken angefordert und den HTTP-Anforderungen über den Autorisierungsheader hinzugefügt. MSAL kümmert sich um den Erwerb und die Erneuerung von Token.

Bibliotheken

In diesem Tutorial werden die folgenden Bibliotheken verwendet:

Bibliothek Beschreibung
MSAL Angular Microsoft Authentication Library für JavaScript: Angular-Wrapper
MSAL-Browser Microsoft Authentication Library für JavaScript v2: Browserpaket

Den Quellcode für sämtliche MSAL.js-Bibliotheken finden Sie auf GitHub im microsoft-authentication-library-for-js-Repository.

Abrufen des abgeschlossenen Codebeispiels

Möchten Sie stattdessen lieber das abgeschlossene Beispielprojekt für dieses Tutorial herunterladen? Klonen des ms-identity-javascript-angular-spa

git clone https://github.com/Azure-Samples/ms-identity-javascript-angular-spa.git

Wenn Sie mit dem Tutorial fortfahren und die Anwendung selbst erstellen möchten, fahren Sie mit dem nächsten Abschnitt (Registrieren der Anwendungs- und Datensatzbezeichner) fort.

Registrieren der Anwendung und Notieren der Bezeichner

Tipp

Die Schritte in diesem Artikel können je nach dem Portal, mit dem Sie beginnen, geringfügig variieren.

Um die Registrierung abzuschließen, geben Sie einen Namen für Anwendung ein, geben Sie die unterstützten Kontotypen an, und fügen Sie einen Umleitungs-URI hinzu. Nach der Registrierung zeigt Bereich Übersicht der Anwendung die im Quellcode der Anwendung erforderlichen Bezeichner an.

  1. Melden Sie sich beim Microsoft Entra Admin Center mindestens mit der Rolle Anwendungsentwickler an.
  2. Wenn Sie Zugriff auf mehrere Mandanten haben, verwenden Sie das Symbol für Einstellungen im oberen Menü, um zum Mandanten zu wechseln, in dem Sie die Anwendung über das Menü Verzeichnisse + Abonnements registrieren möchten.
  3. Browsen Sie zu Identität>Anwendungen>App-Registrierungen.
  4. Wählen Sie Neue Registrierung aus.
  5. Geben Sie einen Namen für die Anwendung ein, z. B. Angular-SPA-auth-code.
  6. Wählen Sie für Unterstützte Kontotypen die Option Nur Konten in diesem Organisationsverzeichnis aus. Wenn Sie Informationen zu den verschiedenen Kontotypen wünschen, wählen Sie Entscheidungshilfe aus.
  7. Verwenden Sie unter Umleitungs-URI (optional) das Dropdownmenü, um Single-Page-Webanwendung (SPA) auszuwählen, und geben Sie http://localhost:4200 in das Textfeld ein.
  8. Wählen Sie Registrieren.
  9. Der Bereich Übersicht der Anwendung wird angezeigt, wenn die Registrierung abgeschlossen ist. Notieren Sie sich die Verzeichnis-ID (Mandant) und die Anwendungs-ID (Client), die im Quellcode Ihrer Anwendung verwendet werden sollen.

Erstellen Ihres Projekts

  1. Öffnen Sie Visual Studio Code.

  2. Wählen Sie Datei>Ordner öffnen .... Navigieren Sie zu dem Speicherort, an dem Sie Ihr Projekt erstellen möchten, und wählen Sie ihn aus.

  3. Öffnen Sie ein neues Terminal, indem Sie Terminal>Neues Terminal auswählen.

    1. Möglicherweise müssen Sie die Terminaltypen wechseln. Wählen Sie den Pfeil nach unten neben dem Symbol + im Terminal aus, und wählen Sie Eingabeaufforderung aus.
  4. Führen Sie die folgenden Befehle aus, um ein neues Angular-Projekt mit dem Namen msal-angular-tutorial zu erstellen, Angular Material-Komponentenbibliotheken, MSAL Browser und MSAL Angular zu installieren und Start- und Profilkomponenten zu generieren.

    npm install -g @angular/cli
    ng new msal-angular-tutorial --routing=true --style=css --strict=false
    cd msal-angular-tutorial
    npm install @angular/material @angular/cdk
    npm install @azure/msal-browser @azure/msal-angular
    ng generate component home
    ng generate component profile
    

Konfigurieren der Anwendung und Bearbeiten der Basisbenutzeroberfläche

  1. Öffnen Sie src/app/app.module.ts. MsalModule und MsalInterceptor müssen zusammen mit der Konstante isIE zu imports hinzugefügt werden. Sie fügen auch die Materialmodule hinzu. Ersetzen Sie den gesamten Inhalt der Datei durch folgenden Codeschnipsel:

    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 { MsalModule, MsalRedirectComponent } from "@azure/msal-angular";
    import { PublicClientApplication } from "@azure/msal-browser";
    
    const isIE =
      window.navigator.userAgent.indexOf("MSIE ") > -1 ||
      window.navigator.userAgent.indexOf("Trident/") > -1;
    
    @NgModule({
      declarations: [AppComponent, HomeComponent, ProfileComponent],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        MatButtonModule,
        MatToolbarModule,
        MatListModule,
        MsalModule.forRoot(
          new PublicClientApplication({
            auth: {
              clientId: "Enter_the_Application_Id_here", // Application (client) ID from the app registration
              authority:
                "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here", // The Azure cloud instance and the app's sign-in audience (tenant ID, common, organizations, or consumers)
              redirectUri: "Enter_the_Redirect_Uri_Here", // This is your redirect URI
            },
            cache: {
              cacheLocation: "localStorage",
              storeAuthStateInCookie: isIE, // Set to true for Internet Explorer 11
            },
          }),
          null,
          null
        ),
      ],
      providers: [],
      bootstrap: [AppComponent, MsalRedirectComponent],
    })
    export class AppModule {}
    
  2. Ersetzen Sie die folgenden Werte durch die Werte, die Sie aus dem Microsoft Entra Admin Center erhalten haben. Weitere Informationen zu den verfügbaren konfigurierbaren Optionen finden Sie unter Initialisieren von Clientanwendungen.

    • clientId – Der Bezeichner der Anwendung, auch Client genannt. Ersetzen Sie Enter_the_Application_Id_Here durch den Wert Anwendungs-ID (Client), der zuvor auf der Übersichtsseite der registrierten Anwendung aufgezeichnet wurde.
    • authority – Diese besteht aus zwei Teilen:
      • Die Instanz ist der Endpunkt des Cloudanbieters. Geben Sie für die Azure-Hauptcloud oder für die globale Azure-Cloud https://login.microsoftonline.com ein. Überprüfen Sie die verschiedenen verfügbaren Endpunkte unter Nationale Clouds.
      • Die Mandanten-ID ist der Bezeichner des Mandanten, in dem die Anwendung registriert ist. Ersetzen Sie _Enter_the_Tenant_Info_Here durch den Wert Verzeichnis-ID (Mandant), der zuvor auf der Übersichtsseite der registrierten Anwendung aufgezeichnet wurde.
    • redirectUri: Der Ort, an den der Autorisierungsserver Benutzer*innen leitet, sobald die App erfolgreich autorisiert und ein Autorisierungscode oder Zugriffstoken zugewiesen wurde. Ersetzen Sie Enter_the_Redirect_Uri_Here durch http://localhost:4200.
  3. Öffnen Sie src/app/app-routing.module.ts, und fügen Sie Routen zu den Komponenten home und profile hinzu. Ersetzen Sie den gesamten Inhalt der Datei durch folgenden Codeschnipsel:

    import { NgModule } from "@angular/core";
    import { Routes, RouterModule } from "@angular/router";
    import { BrowserUtils } from "@azure/msal-browser";
    import { HomeComponent } from "./home/home.component";
    import { ProfileComponent } from "./profile/profile.component";
    
    const routes: Routes = [
      {
        path: "profile",
        component: ProfileComponent,
      },
      {
        path: "",
        component: HomeComponent,
      },
    ];
    
    const isIframe = window !== window.parent && !window.opener;
    
    @NgModule({
      imports: [
        RouterModule.forRoot(routes, {
          // Don't perform initial navigation in iframes or popups
          initialNavigation:
            !BrowserUtils.isInIframe() && !BrowserUtils.isInPopup()
              ? "enabledNonBlocking"
              : "disabled", // Set to enabledBlocking to use Angular Universal
        }),
      ],
      exports: [RouterModule],
    })
    export class AppRoutingModule {}
    
  4. Öffnen Sie src/app/app.component.html und ersetzen Sie den vorhandenen Code durch den folgenden Ausschnitt:

    <mat-toolbar color="primary">
      <a class="title" href="/">{{ title }}</a>
    
      <div class="toolbar-spacer"></div>
    
      <a mat-button [routerLink]="['profile']">Profile</a>
    
      <button mat-raised-button *ngIf="!loginDisplay" (click)="login()">Login</button>
    
    </mat-toolbar>
    <div class="container">
      <!--This is to avoid reload during acquireTokenSilent() because of hidden iframe -->
      <router-outlet *ngIf="!isIframe"></router-outlet>
    </div>
    
  5. Öffnen Sie src/style.css, um die CSS-Formatierung zu definieren:

    @import "~@angular/material/prebuilt-themes/deeppurple-amber.css";
    
    html,
    body {
      height: 100%;
    }
    body {
      margin: 0;
      font-family: Roboto, "Helvetica Neue", sans-serif;
    }
    .container {
      margin: 1%;
    }
    
  6. Öffnen Sie src/app/app.component.css, um der Anwendung CSS-Formatierung hinzuzufügen:

    .toolbar-spacer {
      flex: 1 1 auto;
    }
    
    a.title {
      color: white;
    }
    

Anmelden mit Hilfe von Popups

  1. Öffnen Sie src/app/app.component.ts und ersetzen Sie den Inhalt der Datei durch den folgenden Ausschnitt, um einen Benutzenden über ein Popup-Fenster anzumelden:

    import { MsalService } from '@azure/msal-angular';
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
    
      constructor(private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
      }
    
      login() {
        this.authService.loginPopup()
          .subscribe({
            next: (result) => {
              console.log(result);
              this.setLoginDisplay();
            },
            error: (error) => console.log(error)
          });
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    }
    

Anmelden mittels Umleitungen

  1. Aktualisieren Sie src/app/app.module.ts, um ein Bootstrapping für MsalRedirectComponent durchzuführen. Dies ist eine dedizierte Umleitungskomponente zur Verarbeitung von Umleitungen. Ändern Sie den MsalModule-Import und AppComponent-Bootstrap so, dass er dem folgenden Ausschnitt ähnelt:

    ...
    import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import
    ...
      bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here
    ...
    
  2. Öffnen Sie src/index.html, und ersetzen Sie den gesamten Inhalt der Datei durch den folgenden Codeschnipsel, der den Selektor <app-redirect> hinzufügt:

    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>msal-angular-tutorial</title>
      <base href="/">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root></app-root>
      <app-redirect></app-redirect>
    </body>
    </html>
    
  3. Öffnen Sie src/app/app.component.ts und ersetzen Sie den Code durch den folgenden Ausschnitt, um Benutzende mithilfe einer Vollbild-Weiterleitung anzumelden:

    import { MsalService } from '@azure/msal-angular';
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
    
      constructor(private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
      }
    
      login() {
        this.authService.loginRedirect();
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    }
    
  4. Öffnen Sie src/app/home/home.component.ts und ersetzen Sie den gesamten Inhalt der Datei durch den folgenden Ausschnitt, um das LOGIN_SUCCESS-Ereignis zu abonnieren:

    import { Component, OnInit } from '@angular/core';
    import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
    import { EventMessage, EventType, InteractionStatus } from '@azure/msal-browser';
    import { filter } from 'rxjs/operators';
    
    @Component({
      selector: 'app-home',
      templateUrl: './home.component.html',
      styleUrls: ['./home.component.css']
    })
    export class HomeComponent implements OnInit {
      constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }
    
      ngOnInit(): void {
        this.msalBroadcastService.msalSubject$
          .pipe(
            filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
          )
          .subscribe((result: EventMessage) => {
            console.log(result);
          });
      }
    }
    

Bedingtes Rendern

Um sicherzustellen, dass bestimmte Komponenten der Benutzeroberfläche (UI) nur für authentifizierte Benutzende angezeigt werden, müssen Komponenten den MsalBroadcastService abonnieren, um zu überprüfen, ob Benutzende angemeldet sind und ob die Interaktion abgeschlossen ist.

  1. Fügen Sie MsalBroadcastService zu src/app/app.component.ts hinzu, und abonnieren Sie das observable-Element inProgress$, um vor dem Rendern der Benutzeroberfläche zu überprüfen, ob die Interaktion abgeschlossen und ein Konto angemeldet ist. Ihr Code sollte jetzt folgendermaßen aussehen:

    import { Component, OnInit, OnDestroy } from '@angular/core';
    import { MsalService, MsalBroadcastService } from '@azure/msal-angular';
    import { InteractionStatus } from '@azure/msal-browser';
    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 {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        this.authService.loginRedirect();
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    
  2. Aktualisieren Sie den Code in src/app/home/home.component.ts, um ebenfalls zu überprüfen, ob die Interaktion abgeschlossen ist, bevor die Benutzeroberfläche aktualisiert wird. Ihr Code sollte jetzt folgendermaßen aussehen:

    import { Component, OnInit } from '@angular/core';
    import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
    import { EventMessage, EventType, InteractionStatus } from '@azure/msal-browser';
    import { filter } from 'rxjs/operators';
    
    @Component({
      selector: 'app-home',
      templateUrl: './home.component.html',
      styleUrls: ['./home.component.css']
    })
    export class HomeComponent implements OnInit {
      loginDisplay = false;
    
      constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }
    
      ngOnInit(): void {
        this.msalBroadcastService.msalSubject$
          .pipe(
            filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
          )
          .subscribe((result: EventMessage) => {
            console.log(result);
          });
    
        this.msalBroadcastService.inProgress$
          .pipe(
            filter((status: InteractionStatus) => status === InteractionStatus.None)
          )
          .subscribe(() => {
            this.setLoginDisplay();
          })
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    }
    
  3. Ersetzen Sie den Code in src/app/home/home.component.html durch die folgenden bedingten Anzeigen:

    <div *ngIf="!loginDisplay">
        <p>Please sign-in to see your profile information.</p>
    </div>
    
    <div *ngIf="loginDisplay">
        <p>Login successful!</p>
        <p>Request your profile information by clicking Profile above.</p>
    </div>
    

Implementieren von Angular Guard

Mit der Klasse MsalGuard können Sie Routen schützen und vor dem Zugriff auf die geschützte Route eine Authentifizierung erzwingen. Mit den folgenden Schritten wird MsalGuard der Route Profile hinzugefügt. Der Schutz der Route Profile bedeutet Folgendes: Auch wenn sich Benutzer*innen nicht über die Schaltfläche Login anmelden, werden sie vor der Anzeige der Seite Profile von MsalGuard mittels Popup oder Umleitung zur Authentifizierung aufgefordert, wenn sie versuchen, auf die Route Profile zuzugreifen oder die Schaltfläche Profile auszuwählen.

MsalGuard ist eine Komfortklasse zur Verbesserung der Benutzerfreundlichkeit. Sie sollte jedoch nicht als Sicherheitsfeature verwendet werden. Bei Angriffen können clientseitige Wächter möglicherweise umgangen werden. Stellen Sie daher sicher, dass der Server keine Daten zurückgibt, auf die die Benutzer*innen keinen Zugriff haben sollen.

  1. Fügen Sie Ihrer Anwendung in src/app/app.module.ts die Klasse MsalGuard als Anbieter hinzu, und fügen Sie die Konfigurationen für MsalGuard hinzu. Bereiche, die später zum Abrufen von Token benötigt werden, können in authRequest angegeben werden, und die Art der Interaktion für den Wächter kann auf Redirect oder Popup festgelegt werden. Ihr Code sollte wie folgt aussehen:

    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 {
      MsalModule,
      MsalRedirectComponent,
      MsalGuard,
    } from "@azure/msal-angular"; // MsalGuard added to imports
    import {
      PublicClientApplication,
      InteractionType,
    } from "@azure/msal-browser"; // InteractionType added to imports
    
    const isIE =
      window.navigator.userAgent.indexOf("MSIE ") > -1 ||
      window.navigator.userAgent.indexOf("Trident/") > -1;
    
    @NgModule({
      declarations: [AppComponent, HomeComponent, ProfileComponent],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        MatButtonModule,
        MatToolbarModule,
        MatListModule,
        MsalModule.forRoot(
          new PublicClientApplication({
            auth: {
              clientId: "Enter_the_Application_Id_here",
              authority:
                "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here",
              redirectUri: "Enter_the_Redirect_Uri_Here",
            },
            cache: {
              cacheLocation: "localStorage",
              storeAuthStateInCookie: isIE,
            },
          }),
          {
            interactionType: InteractionType.Redirect, // MSAL Guard Configuration
            authRequest: {
              scopes: ["user.read"],
            },
          },
          null
        ),
      ],
      providers: [
        MsalGuard, // MsalGuard added as provider here
      ],
      bootstrap: [AppComponent, MsalRedirectComponent],
    })
    export class AppModule {}
    
  2. Legen Sie MsalGuard in src/app/app-routing.module.ts für die Routen fest, die Sie schützen möchten:

    import { NgModule } from "@angular/core";
    import { Routes, RouterModule } from "@angular/router";
    import { BrowserUtils } from "@azure/msal-browser";
    import { HomeComponent } from "./home/home.component";
    import { ProfileComponent } from "./profile/profile.component";
    import { MsalGuard } from "@azure/msal-angular";
    
    const routes: Routes = [
      {
        path: "profile",
        component: ProfileComponent,
        canActivate: [MsalGuard],
      },
      {
        path: "",
        component: HomeComponent,
      },
    ];
    
    const isIframe = window !== window.parent && !window.opener;
    
    @NgModule({
      imports: [
        RouterModule.forRoot(routes, {
          // Don't perform initial navigation in iframes or popups
          initialNavigation:
            !BrowserUtils.isInIframe() && !BrowserUtils.isInPopup()
              ? "enabledNonBlocking"
              : "disabled", // Set to enabledBlocking to use Angular Universal
        }),
      ],
      exports: [RouterModule],
    })
    export class AppRoutingModule {}
    
  3. Passen Sie die Anmeldeaufrufe in src/app/app.component.ts an, um authRequest in den Wächterkonfigurationen festzulegen. Ihr Code sollte nun wie folgt aussehen:

    import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
    import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
    import { InteractionStatus, RedirectRequest } from '@azure/msal-browser';
    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 {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        if (this.msalGuardConfig.authRequest){
          this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest);
        } else {
          this.authService.loginRedirect();
        }
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    

Abrufen eines Token

Interceptor von Angular

MSAL Angular verfügt über eine Interceptor-Klasse, mit der automatisch Token für ausgehende Anforderungen bezogen werden, bei denen der http-Client von Angular für bekannte geschützte Ressourcen verwendet wird.

  1. Fügen Sie Ihrer Anwendung in src/app/app.module.ts die Klasse Interceptor als Anbieter sowie die zugehörigen Konfigurationen hinzu. Ihr Code sollte nun wie folgt aussehen:

    import { BrowserModule } from "@angular/platform-browser";
    import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
    import { NgModule } from "@angular/core";
    import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http"; // Import
    
    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 {
      MsalModule,
      MsalRedirectComponent,
      MsalGuard,
      MsalInterceptor,
    } from "@azure/msal-angular"; // Import MsalInterceptor
    import {
      InteractionType,
      PublicClientApplication,
    } from "@azure/msal-browser";
    
    const isIE =
      window.navigator.userAgent.indexOf("MSIE ") > -1 ||
      window.navigator.userAgent.indexOf("Trident/") > -1;
    
    @NgModule({
      declarations: [AppComponent, HomeComponent, ProfileComponent],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        MatButtonModule,
        MatToolbarModule,
        MatListModule,
        HttpClientModule,
        MsalModule.forRoot(
          new PublicClientApplication({
            auth: {
              clientId: "Enter_the_Application_Id_Here",
              authority:
                "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here",
              redirectUri: "Enter_the_Redirect_Uri_Here",
            },
            cache: {
              cacheLocation: "localStorage",
              storeAuthStateInCookie: isIE,
            },
          }),
          {
            interactionType: InteractionType.Redirect,
            authRequest: {
              scopes: ["user.read"],
            },
          },
          {
            interactionType: InteractionType.Redirect, // MSAL Interceptor Configuration
            protectedResourceMap: new Map([
              ["Enter_the_Graph_Endpoint_Here/v1.0/me", ["user.read"]],
            ]),
          }
        ),
      ],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: MsalInterceptor,
          multi: true,
        },
        MsalGuard,
      ],
      bootstrap: [AppComponent, MsalRedirectComponent],
    })
    export class AppModule {}
    

    Die geschützten Ressourcen werden als protectedResourceMap bereitgestellt. Bei den URLs, die Sie in der protectedResourceMap-Sammlung angeben, muss die Groß-/Kleinschreibung beachtet werden. Fügen Sie für jede Ressource Bereiche hinzu, die für die Rückgabe im Zugriffstoken angefordert werden.

    Beispiel:

    • ["user.read"] für Microsoft Graph
    • ["<Application ID URL>/scope"] für benutzerdefinierte Web-APIs (api://<Application ID>/access_as_user)

    Ändern Sie die Werte in protectedResourceMap wie im Anschluss beschrieben:

    • Enter_the_Graph_Endpoint_Here ist die Instanz der Microsoft Graph-API, mit der die Anwendung kommunizieren soll. Für den globalen Endpunkt der Microsoft Graph-API ersetzen Sie diese Zeichenfolge durch https://graph.microsoft.com. Informationen zu Endpunkten in nationalen Cloudbereitstellungen finden Sie in der Microsoft Graph Dokumentation unter Bereitstellungen nationaler Clouds.
  2. Ersetzen Sie den Code in src/app/profile/profile.component.ts, um ein Benutzerprofil mit einer HTTP-Anforderung abzurufen, und ersetzen Sie GRAPH_ENDPOINT durch den Microsoft Graph-Endpunkt:

    import { Component, OnInit } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    
    const GRAPH_ENDPOINT = 'Enter_the_Graph_Endpoint_Here/v1.0/me';
    
    type ProfileType = {
      givenName?: string,
      surname?: string,
      userPrincipalName?: string,
      id?: string
    };
    
    @Component({
      selector: 'app-profile',
      templateUrl: './profile.component.html',
      styleUrls: ['./profile.component.css']
    })
    export class ProfileComponent implements OnInit {
      profile!: ProfileType;
    
      constructor(
        private http: HttpClient
      ) { }
    
      ngOnInit() {
        this.getProfile();
      }
    
      getProfile() {
        this.http.get(GRAPH_ENDPOINT)
          .subscribe(profile => {
            this.profile = profile;
          });
      }
    }
    
  3. Ersetzen Sie die Benutzeroberfläche in src/app/profile/profile.component.html, um Profilinformationen anzuzeigen:

    <div>
        <p><strong>First Name: </strong> {{profile?.givenName}}</p>
        <p><strong>Last Name: </strong> {{profile?.surname}}</p>
        <p><strong>Email: </strong> {{profile?.userPrincipalName}}</p>
        <p><strong>Id: </strong> {{profile?.id}}</p>
    </div>
    

Abmelden

  1. Aktualisieren Sie den Code in src/app/app.component.html zur bedingten Anzeige einer Schaltfläche vom Typ Logout:

    <mat-toolbar color="primary">
      <a class="title" href="/">{{ title }}</a>
    
      <div class="toolbar-spacer"></div>
    
      <a mat-button [routerLink]="['profile']">Profile</a>
    
      <button mat-raised-button *ngIf="!loginDisplay" (click)="login()">Login</button>
      <button mat-raised-button *ngIf="loginDisplay" (click)="logout()">Logout</button>
    
    </mat-toolbar>
    <div class="container">
      <!--This is to avoid reload during acquireTokenSilent() because of hidden iframe -->
      <router-outlet *ngIf="!isIframe"></router-outlet>
    </div>
    

Abmelden mittels Umleitungen

  1. Aktualisieren Sie den Code in src/app/app.component.ts, um einen Benutzer unter Verwendung von Umleitungen abzumelden:

    import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
    import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
    import { InteractionStatus, RedirectRequest } from '@azure/msal-browser';
    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 {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        if (this.msalGuardConfig.authRequest){
          this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest);
        } else {
          this.authService.loginRedirect();
        }
      }
    
      logout() { // Add log out function here
        this.authService.logoutRedirect({
          postLogoutRedirectUri: 'http://localhost:4200'
        });
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    

Durch Pop-Ups abmelden

  1. Aktualisieren Sie den Code in src/app/app.component.ts, um einen Benutzer unter Verwendung von Popups abzumelden:

    import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
    import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
    import { InteractionStatus, PopupRequest } from '@azure/msal-browser';
    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 {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        if (this.msalGuardConfig.authRequest){
          this.authService.loginPopup({...this.msalGuardConfig.authRequest} as PopupRequest)
            .subscribe({
              next: (result) => {
                console.log(result);
                this.setLoginDisplay();
              },
              error: (error) => console.log(error)
            });
        } else {
          this.authService.loginPopup()
            .subscribe({
              next: (result) => {
                console.log(result);
                this.setLoginDisplay();
              },
              error: (error) => console.log(error)
            });
        }
      }
    
      logout() { // Add log out function here
        this.authService.logoutPopup({
          mainWindowRedirectUri: "/"
        });
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    

Testen Ihres Codes

  1. Starten Sie den Webserver, um an dem Port zu lauschen, indem Sie an einer Eingabeaufforderung im Anwendungsordner die folgenden Befehle ausführen:

    npm install
    npm start
    
  2. Geben Sie in Ihrem Browser http://localhost:4200 ein. Daraufhin sollte eine Seite wie folgende angezeigt werden.

    Webbrowser mit dem Anmeldedialogfeld.

  3. Wählen Sie Akzeptieren aus, um der App Berechtigungen für Ihr Profil zu erteilen. Dies geschieht, wenn Sie sich zum ersten Mal anmelden.

    Im Webbrowser angezeigtes Inhaltsdialogfeld.

  4. Wenn Sie in die angeforderten Berechtigungen einwilligen, wird von der Webanwendung eine Seite für die erfolgreiche Anmeldung angezeigt:

    Ergebnisse einer erfolgreichen Anmeldung im Webbrowser.

  5. Wählen Sie die Option Profil aus, um die Benutzerprofilinformationen anzuzeigen, die in der Antwort des Aufrufs der Microsoft Graph-API zurückgegeben werden:

    Im Browser angezeigte Profilinformationen aus Microsoft Graph.

Hinzufügen von Bereichen und delegierten Berechtigungen

Die Microsoft Graphs-API benötigt den Bereich User.Read, um das Profil von Benutzenden zu lesen. Der Bereich User.Read wird automatisch jeder App-Registrierung hinzugefügt. Andere APIs für Microsoft Graph sowie benutzerdefinierte APIs für Ihren Back-End-Server erfordern möglicherweise andere Bereiche. Zum Beispiel benötigt die Microsoft Graphs-API den Bereich Mail.Read, um die E-Mail-Adresse der Benutzenden aufzulisten.

Wenn Sie Bereiche hinzufügen, werden Ihre Benutzer*innen möglicherweise aufgefordert, eine weitere Einwilligung für die hinzugefügten Bereiche zu erteilen.

Hinweis

Wenn Sie die Anzahl der Bereiche erhöhen, werden Benutzer ggf. zu weiteren Genehmigungen aufgefordert.

Hilfe und Support

Wenn Sie Hilfe benötigen, ein Problem melden möchten oder sich über Ihre Supportoptionen informieren möchten, finden Sie weitere Informationen unter Hilfe und Support für Entwickler.

Nächste Schritte

  • Erfahren Sie mehr, indem Sie eine React-Single-Page-Webanwendung (Single-Page Application, SPA) erstellen, die Benutzer bei der folgenden mehrteiligen Lernprogrammreihe anmeldet.