Zelfstudie: Gebruikers aanmelden en de Microsoft Graph-API aanroepen vanuit een Angular-app met één pagina met behulp van de verificatiecodestroom
In deze zelfstudie bouwt u een Angular-toepassing met één pagina die gebruikers aanmeldt en de Microsoft Graph API aanroept met behulp van de autorisatiecodestroom met PKCE. De SPA die u bouwt, maakt gebruik van de Microsoft Authentication Library (MSAL) voor Angular v2.
In deze zelfstudie:
- De toepassing registreren in het Microsoft Entra-beheercentrum
- Een Angular-project maken met
npm
- Code toevoegen voor de ondersteuning van het aan- en afmelden van gebruikers
- Code toevoegen om de Microsoft Graph API aan te roepen
- De app testen
MSAL Angular v2 verbetert met MSAL Angular v1 door de autorisatiecodestroom te ondersteunen met PKCE in de browser in plaats van de impliciete toekenningsstroom. U wordt aangeraden de autorisatiecodestroom met PKCE te gebruiken voor toepassingen met één pagina (SPA's), omdat deze veiliger is dan de impliciete stroom. MSAL Angular v2 biedt GEEN ondersteuning voor de impliciete stroom.
Vereisten
- Node.js- voor het uitvoeren van een lokale webserver.
- Visual Studio Code of een andere editor voor het wijzigen van projectbestanden.
Hoe de voorbeeld-app werkt
Met de voorbeeldtoepassing die in deze zelfstudie wordt gemaakt, kan een Angular SPA een query uitvoeren bij de Microsoft Graph API of een web-API die tokens accepteert die zijn uitgegeven door het Microsoft-identiteitsplatform. Hierbij wordt de Microsoft Authentication Library (MSAL) voor Angular v2 gebruikt, een wrapper van de MSAL.js v2-bibliotheek. MET MSAL Angular kunnen Angular 9+-toepassingen zakelijke gebruikers verifiëren met behulp van Microsoft Entra-id, en ook gebruikers met Microsoft-accounts en sociale identiteiten, zoals Facebook, Google en LinkedIn. De bibliotheek zorgt er ook voor dat toepassingen toegang krijgen tot Microsoft-cloudservices en Microsoft Graph.
Wanneer in dit scenario een gebruiker zich aanmeldt, wordt er een toegangstoken gevraagd en toegevoegd aan HTTP-aanvragen via de autorisatie-header. Tokens worden opgehaald en verlengd door MSAL.
Bibliotheken
Deze zelfstudie maakt gebruik van de volgende bibliotheken:
Bibliotheek | Beschrijving |
---|---|
MSAL Angular | Micro Authentication Library voor JavaScript Angular Wrapper |
MSAL Browser | Microsoft Authentication Library voor JavaScript v2-browserpakket |
U vindt de broncode voor alle MSAL.js bibliotheken in de microsoft-authentication-library-for-js
opslagplaats op GitHub.
Het voltooide codevoorbeeld ophalen
Wilt u in plaats daarvan het voltooide voorbeeldproject voor deze zelfstudie downloaden? De ms-identity-javascript-angular-spa klonen
git clone https://github.com/Azure-Samples/ms-identity-javascript-angular-spa.git
Als u wilt doorgaan met de zelfstudie en de toepassing zelf wilt bouwen, gaat u verder met de volgende sectie, De toepassing en record-id's registreren.
De toepassings- en record-id's registreren
Tip
Stappen in dit artikel kunnen enigszins variëren op basis van de portal waaruit u begint.
Als u de registratie wilt voltooien, geeft u de toepassing een naam op, geeft u de ondersteunde accounttypen op en voegt u een omleidings-URI toe. Nadat de toepassing is geregistreerd, worden in het deelvenster Overzicht van de toepassing de id's weergegeven die nodig zijn in de broncode van de toepassing.
- Meld u als toepassingsontwikkelaar aan bij het Microsoft Entra-beheercentrum.
- Als u toegang hebt tot meerdere tenants, gebruikt u het pictogram Instellingen in het bovenste menu om over te schakelen naar de tenant waarin u de toepassing wilt registreren in het menu Mappen en abonnementen.
- Blader naar identiteitstoepassingen>> App-registraties.
- Selecteer Nieuwe registratie.
- Voer een naam in voor de toepassing, zoals Angular-SPA-auth-code.
- Bij Ondersteunde accounttypen selecteert u Enkel accounts in deze organisatieadreslijst. Selecteer de optie Help mij kiezen voor informatie over verschillende accounttypen.
- Gebruik onder Omleidings-URI (optioneel) de vervolgkeuzelijst om toepassing met één pagina (SPA) te selecteren en voer
http://localhost:4200
het tekstvak in. - Selecteer Registreren.
- Het deelvenster Overzicht van de toepassing wordt weergegeven wanneer de registratie is voltooid. Noteer de map-id (tenant) en de toepassings-id (client) die moet worden gebruikt in de broncode van uw toepassing.
Uw project maken
Open Visual Studio Code, selecteer Map>openen.... Navigeer naar en selecteer de locatie waar u uw project wilt maken.
Open een nieuwe terminal door Terminal>New Terminal te selecteren.
- Mogelijk moet u van terminaltype wisselen. Selecteer de pijl-omlaag naast het + pictogram in de terminal en selecteer Opdrachtprompt.
Voer de volgende opdrachten uit om een nieuw Angular-project te maken met de naam
msal-angular-tutorial
, installeer Angular Material-onderdeelbibliotheken, MSAL Browser, MSAL Angular en genereer basis- en profielonderdelen.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
De toepassing configureren en de basisgebruikersinterface bewerken
Open src/app/app.module.ts. De
MsalModule
enMsalInterceptor
moeten worden toegevoegd aanimports
samen met deisIE
constante. U voegt ook de materiaalmodules toe. Vervang de volledige inhoud van het bestand door het volgende codefragment: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 {}
Vervang de volgende waarden door de waarden die zijn verkregen uit het Microsoft Entra-beheercentrum. Raadpleeg Clienttoepassingen initialiseren voor meer informatie over beschikbare opties die u kunt configureren.
clientId
- De id van de toepassing, ook wel de client genoemd. VervangEnter_the_Application_Id_Here
door de waarde van de toepassings-id (client) die eerder is vastgelegd op de overzichtspagina van de geregistreerde toepassing.authority
- Dit bestaat uit twee delen:- Het exemplaar is het eindpunt van de cloudprovider. Voer
https://login.microsoftonline.com
in voor de primaire of algemene Azure-cloud. Neem contact op met de verschillende beschikbare eindpunten in nationale clouds. - De tenant-id is de id van de tenant waar de toepassing is geregistreerd. Vervang de
_Enter_the_Tenant_Info_Here
waarde van de map-id (tenant) die eerder is vastgelegd op de overzichtspagina van de geregistreerde toepassing.
- Het exemplaar is het eindpunt van de cloudprovider. Voer
redirectUri
- de locatie waar de autorisatieserver de gebruiker verzendt zodra de app is geautoriseerd en een autorisatiecode of toegangstoken heeft verleend. VervangEnter_the_Redirect_Uri_Here
doorhttp://localhost:4200
.
Open src/app/app-routing.module.ts en voeg routes toe aan de basis - en profielonderdelen . Vervang de volledige inhoud van het bestand door het volgende codefragment:
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 {}
Open src/app/app.component.html en vervang de bestaande code door het volgende:
<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>
Open src/style.css om de CSS te definiëren:
@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%; }
Open src/app/app.component.css om CSS-stijl toe te voegen aan de toepassing:
.toolbar-spacer { flex: 1 1 auto; } a.title { color: white; }
Aanmelden met pop-ups
Open src/app/app.component.ts en vervang de inhoud van het bestand door het volgende om een gebruiker aan te melden met behulp van een pop-upvenster:
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; } }
Aanmelden met omleidingen
Werk src/app/app.module.ts bij om de
MsalRedirectComponent
te bootstrappen. Dit is een speciaal omleidingsonderdeel dat omleidingen verwerkt. Wijzig deMsalModule
import enAppComponent
bootstrap zodat deze er ongeveer als volgt uitziet:... import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import ... bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here ...
Open src/index.html en vervang de volledige inhoud van het bestand door het volgende fragment, waarmee de
<app-redirect>
selector wordt toegevoegd:<!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>
Open src/app/app.component.ts en vervang de code door het volgende om een gebruiker aan te melden met behulp van een omleiding in een volledig frame:
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; } }
Navigeer naar src/app/home/home.component.ts en vervang de volledige inhoud van het bestand door het volgende codefragment om u te abonneren op de
LOGIN_SUCCESS
gebeurtenis: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); }); } }
Voorwaardelijke weergave
Als u bepaalde gebruikersinterface (UI) alleen wilt weergeven voor geverifieerde gebruikers, moeten onderdelen zich abonneren op de MsalBroadcastService
gebruiker om te zien of gebruikers zijn aangemeld en de interactie is voltooid.
Voeg de
MsalBroadcastService
toe aan src/app/app.component.ts en abonneer u op de waarneembare parameterinProgress$
om te controleren of de interactie is voltooid en of er een account is aangemeld voordat de gebruikersinterface wordt weergegeven. Uw code moet er nu als volgt uitzien: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(); } }
Werk de code in src/app/home/home.component.ts bij om ook te controleren of de interactie is voltooid voordat de gebruikersinterface wordt bijgewerkt. Uw code moet er nu als volgt uitzien:
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; } }
Vervang de code in src/app/home/home.component.html door de volgende voorwaardelijke weergaven:
<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>
Angular Guard implementeren
De MsalGuard
klasse is een klasse die u kunt gebruiken om routes te beveiligen en verificatie te vereisen voordat u toegang krijgt tot de beveiligde route. Met de volgende stappen voegt u de MsalGuard
route toe Profile
. Het beveiligen van de Profile
route betekent dat zelfs als een gebruiker zich niet aanmeldt met behulp van de Login
knop, als hij de Profile
route probeert te openen of de Profile
knop selecteert, de MsalGuard
gebruiker wordt gevraagd om zich te verifiëren via pop-up of omleiding voordat de Profile
pagina wordt weergegeven.
MsalGuard
is een handige klasse die u kunt gebruiken om de gebruikerservaring te verbeteren, maar deze moet niet worden vertrouwd voor beveiliging. Aanvallers kunnen mogelijk beveiliging aan de clientzijde omzeilen en u moet ervoor zorgen dat de server geen gegevens retourneert waartoe de gebruiker geen toegang mag krijgen.
Voeg de klasse
MsalGuard
toe als provider in uw toepassing in src/app/app.module.ts en voeg de configuraties voor deMsalGuard
toe. Bereiken die nodig zijn om later tokens te verkrijgen, kunnen worden opgegeven in deauthRequest
, en het type interactie voor de beveiliging kan worden ingesteld opRedirect
ofPopup
. Uw code moet er als volgt uitzien: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 {}
Stel de
MsalGuard
in voor de routes die u wilt beveiligen in src/app/app-routing.module.ts: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 {}
Pas de aanmeldingsaanroepen in src/app/app.component.ts aan om rekening te houden met de
authRequest
die is ingesteld in de beveiligingsconfiguraties. Uw code moet er nu als volgt uitzien: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(); } }
Een token verkrijgen
Angular-interceptor
MSAL Angular biedt de klasse Interceptor
die automatisch tokens ophaalt voor uitgaande aanvragen naar bekende beveiligde bronnen en die gebruikmaken van de Angular http
-client.
Voeg de klasse
Interceptor
als provider toe aan uw toepassing in src/app/app.module.ts, met de bijbehorende configuraties. Uw code moet er nu als volgt uitzien: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 {}
De beveiligde resources worden geleverd als een
protectedResourceMap
. De URL's die u opgeeft in de verzamelingprotectedResourceMap
zijn hoofdlettergevoelig. Voeg voor elke resource bereiken toe die worden aangevraagd om te worden geretourneerd in het toegangstoken.Voorbeeld:
["user.read"]
voor Microsoft Graph["<Application ID URL>/scope"]
voor aangepaste web-API's (api://<Application ID>/access_as_user
)
Wijzig de waarden in de
protectedResourceMap
, zoals hier wordt beschreven:Enter_the_Graph_Endpoint_Here
is het exemplaar van de Microsoft Graph API waarmee de toepassing moet communiceren. Voor het globale Microsoft Graph API-eindpunt vervangt u deze tekenreeks doorhttps://graph.microsoft.com
. Zie Nationale cloudimplementaties in de Microsoft Graph-documentatie voor eindpunten in nationale cloudimplementaties.
Vervang de code in src/app/profile/profile.component.ts om het profiel van een gebruiker op te halen door een HTTP-aanvraag en vervang de
GRAPH_ENDPOINT
code door het Microsoft Graph-eindpunt: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; }); } }
Vervang de gebruikersinterface in src/app/profile/profile.component.html om profielgegevens weer te geven:
<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>
Afmelden
Werk de code in src/app/app.component.html bij om voorwaardelijk een knop
Logout
weer te geven:<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>
Afmelden met omleidingen
Werk de code in src/app/app.component.ts bij om een gebruiker af te melden met behulp van omleidingen:
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(); } }
Afmelden met pop-ups
Werk de code in src/app/app.component.ts bij om een gebruiker af te melden met behulp van pop-ups:
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(); } }
Uw code testen
Start de webserver om te luisteren naar de poort door de volgende opdrachten in een opdrachtregelprompt in de toepassingsmap uit te voeren:
npm install npm start
Voer in uw browser een
http://localhost:4200
pagina in die er ongeveer als volgt uitziet.Selecteer Accepteren om de app-machtigingen toe te kennen aan uw profiel. Dit gebeurt de eerste keer dat u zich begint aan te melden.
Nadat u toestemming hebt gegeven, wordt in de webtoepassing een geslaagde aanmeldingspagina weergegeven als u toestemming geeft voor de aangevraagde machtigingen.
Selecteer Profiel om de gebruikersprofielgegevens weer te geven die worden geretourneerd in het antwoord van de aanroep naar de Microsoft Graph API:
Bereiken en gedelegeerde toestemmingen toevoegen
De Microsoft Graph-API vereist het bereik User.Read om het profiel van een gebruiker te lezen. Het bereik User.Read wordt automatisch toegevoegd aan elke app-registratie. Voor andere API's voor Microsoft Graph en aangepaste API's voor uw back-endserver zijn mogelijk andere bereiken vereist. De Microsoft Graph API vereist bijvoorbeeld het bereik Mail.Read om de e-mail van de gebruiker op te sommen.
Wanneer u bereiken toevoegt, wordt uw gebruikers mogelijk gevraagd om extra toestemming te geven voor de toegevoegde bereiken.
Notitie
De gebruiker wordt mogelijk gevraagd om aanvullende machtigingen te geven naarmate u het aantal bereiken verhoogt.
Help en ondersteuning
Als u hulp nodig hebt, een probleem wilt melden of meer informatie wilt over uw ondersteuningsopties, raadpleegt u Hulp en ondersteuning voor ontwikkelaars.
Volgende stappen
- Meer informatie vindt u door een React-toepassing met één pagina (SPA) te bouwen waarmee gebruikers worden aangemeld in de volgende reeks meerdelige zelfstudies.
Feedback
https://aka.ms/ContentUserFeedback.
Binnenkort: Gedurende 2024 worden GitHub Issues uitgefaseerd als het feedbackmechanisme voor inhoud. Dit wordt vervangen door een nieuw feedbacksysteem. Ga voor meer informatie naar:Feedback verzenden en bekijken voor