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
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.
- Melden Sie sich beim Microsoft Entra Admin Center mindestens mit der Rolle Anwendungsentwickler an.
- 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.
- Browsen Sie zu Identität>Anwendungen>App-Registrierungen.
- Wählen Sie Neue Registrierung aus.
- Geben Sie einen Namen für die Anwendung ein, z. B. Angular-SPA-auth-code.
- 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.
- 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. - Wählen Sie Registrieren.
- 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
Öffnen Sie Visual Studio Code.
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.
Öffnen Sie ein neues Terminal, indem Sie Terminal>Neues Terminal auswählen.
- 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.
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
Öffnen Sie src/app/app.module.ts.
MsalModule
undMsalInterceptor
müssen zusammen mit der KonstanteisIE
zuimports
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 {}
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 SieEnter_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.
- Die Instanz ist der Endpunkt des Cloudanbieters. Geben Sie für die Azure-Hauptcloud oder für die globale Azure-Cloud
redirectUri
: Der Ort, an den der Autorisierungsserver Benutzer*innen leitet, sobald die App erfolgreich autorisiert und ein Autorisierungscode oder Zugriffstoken zugewiesen wurde. Ersetzen SieEnter_the_Redirect_Uri_Here
durchhttp://localhost:4200
.
Ö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 {}
Ö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>
Ö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%; }
Ö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
Ö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
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 denMsalModule
-Import undAppComponent
-Bootstrap so, dass er dem folgenden Ausschnitt ähnelt:... import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import ... bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here ...
Ö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>
Ö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; } }
Ö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.
Fügen Sie
MsalBroadcastService
zu src/app/app.component.ts hinzu, und abonnieren Sie das observable-ElementinProgress$
, 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(); } }
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; } }
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.
Fügen Sie Ihrer Anwendung in src/app/app.module.ts die Klasse
MsalGuard
als Anbieter hinzu, und fügen Sie die Konfigurationen fürMsalGuard
hinzu. Bereiche, die später zum Abrufen von Token benötigt werden, können inauthRequest
angegeben werden, und die Art der Interaktion für den Wächter kann aufRedirect
oderPopup
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 {}
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 {}
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.
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 derprotectedResourceMap
-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 durchhttps://graph.microsoft.com
. Informationen zu Endpunkten in nationalen Cloudbereitstellungen finden Sie in der Microsoft Graph Dokumentation unter Bereitstellungen nationaler Clouds.
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; }); } }
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
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
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
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
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
Geben Sie in Ihrem Browser
http://localhost:4200
ein. Daraufhin sollte eine Seite wie folgende angezeigt werden.Wählen Sie Akzeptieren aus, um der App Berechtigungen für Ihr Profil zu erteilen. Dies geschieht, wenn Sie sich zum ersten Mal anmelden.
Wenn Sie in die angeforderten Berechtigungen einwilligen, wird von der Webanwendung eine Seite für die erfolgreiche Anmeldung angezeigt:
Wählen Sie die Option Profil aus, um die Benutzerprofilinformationen anzuzeigen, die in der Antwort des Aufrufs der Microsoft Graph-API zurückgegeben werden:
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.