Kurz: Přihlášení uživatelů a volání rozhraní Microsoft Graph API z jednostránkové aplikace Angular (SPA) pomocí toku ověřovacího kódu
V tomto kurzu vytvoříte jednostránkovou aplikaci Angular (SPA), která přihlásí uživatele a zavolá rozhraní Microsoft Graph API pomocí toku autorizačního kódu s PKCE. Služba SPA, kterou vytvoříte, používá knihovnu MICROSOFT Authentication Library (MSAL) pro Angular v2.
V tomto kurzu:
- Registrace aplikace v Centru pro správu Microsoft Entra
- Vytvoření projektu Angular pomocí
npm
- Přidání kódu pro podporu přihlášení a odhlášení uživatele
- Přidání kódu pro volání rozhraní Microsoft Graph API
- Otestování aplikace
MSAL Angular v2 vylepšuje msAL Angular v1 tím, že podporuje tok autorizačního kódu s PKCE v prohlížeči místo implicitního toku udělení. Doporučujeme použít tok autorizačního kódu s pkCE pro jednostránka aplikace (SPA), protože je bezpečnější než implicitní tok. MSAL Angular v2 nepodporuje implicitní tok.
Požadavky
- Node.js pro spuštění místního webového serveru.
- Visual Studio Code nebo jiný editor pro úpravy souborů projektu
Jak funguje ukázková aplikace
Ukázková aplikace vytvořená v tomto kurzu umožňuje angular SPA dotazovat rozhraní Microsoft Graph API nebo webové rozhraní API, které přijímá tokeny vydané platformou Microsoft Identity Platform. Používá knihovnu MSAL (Microsoft Authentication Library) pro Angular v2, obálku knihovny MSAL.js v2. MSAL Angular umožňuje aplikacím Angular 9+ ověřovat podnikové uživatele pomocí Microsoft Entra ID a také uživatelů s účty Microsoft a sociálními identitami, jako jsou Facebook, Google a LinkedIn. Knihovna také umožňuje aplikacím získat přístup ke cloudovým službám Microsoftu a Microsoft Graphu.
V tomto scénáři se po přihlášení uživatele vyžádá přístupový token a přidá se do požadavků HTTP prostřednictvím autorizační hlavičky. Nástroj MSAL zpracovává získání a obnovení tokenů.
Knihovny
V tomto kurzu se používají následující knihovny:
Knihovna | Popis |
---|---|
MSAL Angular | Microsoft Authentication Library for JavaScript Angular Wrapper |
Prohlížeč MSAL | Balíček prohlížeče Microsoft Authentication Library pro JavaScript v2 |
Zdrojový kód pro všechny knihovny MSAL.js najdete v microsoft-authentication-library-for-js
úložišti na GitHubu.
Získání dokončené ukázky kódu
Dáváte přednost stažení dokončeného ukázkového projektu pro tento kurz? Klonování ms-identity-javascript-angular-spa
git clone https://github.com/Azure-Samples/ms-identity-javascript-angular-spa.git
Pokud chcete pokračovat v kurzu a sestavit aplikaci sami, přejděte k další části, zaregistrujte identifikátory aplikace a záznamu.
Registrace identifikátorů aplikace a záznamů
Tip
Postup v tomto článku se může mírně lišit v závislosti na portálu, od který začínáte.
K dokončení registrace zadejte název aplikace, zadejte podporované typy účtů a přidejte identifikátor URI přesměrování. Po registraci se v podokně Přehled aplikace zobrazí identifikátory potřebné ve zdrojovém kódu aplikace.
- Přihlaste se do Centra pro správu Microsoft Entra jako alespoň vývojář aplikací.
- Pokud máte přístup k více tenantům, pomocí ikony Nastavení v horní nabídce přepněte na tenanta, ve kterém chcete aplikaci zaregistrovat z nabídky Adresáře a předplatná.
- Přejděte k aplikacím> identit>Registrace aplikací.
- Vyberte Nová registrace.
- Zadejte název aplikace, například Angular-SPA-auth-code.
- U podporovaných typů účtů vyberte Pouze účty v tomto organizačním adresáři. Pokud chcete získat informace o různých typech účtů, vyberte možnost Nápověda pro výběr .
- V části Identifikátor URI přesměrování (volitelné) pomocí rozevírací nabídky vyberte Jednostránkové aplikace (SPA) a zadejte
http://localhost:4200
do textového pole. - Vyberte Zaregistrovat.
- Po dokončení registrace se zobrazí podokno Přehled aplikace. Poznamenejte si ID adresáře (tenanta) a ID aplikace (klienta), které se má použít ve zdrojovém kódu aplikace.
Vytvoření projektu
Otevřete Visual Studio Code a vyberte >Soubor otevřít složku.... Přejděte a vyberte umístění, ve kterém chcete projekt vytvořit.
Výběrem možnosti Terminál>nový terminál otevřete nový terminál.
- Možná budete muset přepnout typy terminálů. Vyberte šipku + dolů vedle ikony v terminálu a vyberte příkazový řádek.
Spuštěním následujících příkazů vytvořte nový projekt Angular s názvem
msal-angular-tutorial
, nainstalujte knihovny komponent Angular Material, MSAL Browser, MSAL Angular a vygenerujte součásti domů a profilu.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
Konfigurace aplikace a úprava základního uživatelského rozhraní
Otevřete soubor src,app/app.module.ts. Je
MsalModule
potřeba je přidatimports
spolu s konstantouisIE
.MsalInterceptor
Přidáte také moduly materiálu. Celý obsah souboru nahraďte následujícím fragmentem kódu: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 {}
Nahraďte následující hodnoty hodnotami získanými z Centra pro správu Microsoft Entra. Další informace o dostupných konfigurovatelných možnostech naleznete v tématu Inicializace klientských aplikací.
clientId
– Identifikátor aplikace, označovaný také jako klient. NahraďteEnter_the_Application_Id_Here
hodnotou ID aplikace (klienta), která byla zaznamenána dříve ze stránky přehledu registrované aplikace.authority
- Skládá se ze dvou částí:- Instance je koncový bod poskytovatele cloudu. V případě hlavního nebo globálního cloudu Azure zadejte
https://login.microsoftonline.com
. Zkontrolujte různé dostupné koncové body v národních cloudech. - ID tenanta je identifikátor tenanta, ve kterém je aplikace zaregistrovaná.
_Enter_the_Tenant_Info_Here
Hodnotu ID adresáře (tenanta) zaznamenanou dříve na stránce přehledu registrované aplikace nahraďte hodnotou ID adresáře (tenanta).
- Instance je koncový bod poskytovatele cloudu. V případě hlavního nebo globálního cloudu Azure zadejte
redirectUri
– umístění, kde autorizační server odešle uživatele po úspěšném autorizaci aplikace a udělení autorizačního kódu nebo přístupového tokenu. NahraďteEnter_the_Redirect_Uri_Here
http://localhost:4200
.
Otevřete soubor src,app/app-routing.module.ts a přidejte trasy do komponent domů a profilů . Celý obsah souboru nahraďte následujícím fragmentem kódu:
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 {}
Otevřete src/app/app.component.html a nahraďte stávající kód následujícím kódem:
<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>
Otevřete soubor src/style.css a definujte šablony stylů CSS:
@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%; }
Otevřete soubor src,app/app.component.css a přidejte do aplikace styly CSS:
.toolbar-spacer { flex: 1 1 auto; } a.title { color: white; }
Přihlášení pomocí automaticky otevíraných oken
Otevřete soubor src/app/app.component.ts a nahraďte obsah souboru následujícím způsobem, abyste se přihlásili uživatele pomocí automaticky otevíraného okna:
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; } }
Přihlášení pomocí přesměrování
Aktualizujte soubor src,app/app.module.ts pro spuštění
MsalRedirectComponent
souboru . Jedná se o vyhrazenou komponentu přesměrování, která zpracovává přesměrování.MsalModule
Změňte import aAppComponent
bootstrap tak, aby vypadal takto:... import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import ... bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here ...
Otevřete src/index.html a nahraďte celý obsah souboru následujícím fragmentem kódu, který přidá
<app-redirect>
selektor:<!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>
Otevřete soubor src/app/app.component.ts a nahraďte kód následujícím kódem, abyste se přihlásili uživatele pomocí přesměrování na plný rámec:
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; } }
Přejděte na src/app/home/home.component.ts a nahraďte celý obsah souboru následujícím fragmentem kódu a přihlaste se k odběru
LOGIN_SUCCESS
události: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); }); } }
Podmíněné vykreslování
Aby bylo možné vykreslit určité uživatelské rozhraní pouze pro ověřené uživatele, musí se komponenty přihlásit k odběru MsalBroadcastService
, aby se zjistilo, jestli byli přihlášeni uživatelé a interakce byla dokončena.
MsalBroadcastService
Přidejte do src,app/app.component.ts a přihlaste se k odběruinProgress$
pozorovatelného účtu, abyste zkontrolovali, jestli je interakce dokončená, a před vykreslením uživatelského rozhraní je přihlášený účet. Váš kód by teď měl vypadat takto: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(); } }
Aktualizujte kód v souboru src,app/home/home.component.ts a zkontrolujte také, jestli se má před aktualizací uživatelského rozhraní dokončit interakce. Váš kód by teď měl vypadat takto:
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; } }
Nahraďte kód v src/app/home/home.component.html následujícím podmíněným zobrazením:
<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>
Implementace angular Guard
Třída MsalGuard
je ta, kterou můžete použít k ochraně tras a před přístupem k chráněné trase vyžadovat ověření. Následující postup přidá trasu MsalGuard
Profile
. Profile
Ochrana trasy znamená, že i když se uživatel nepřihlásí pomocí Login
tlačítka, pokud se pokusí o přístup k Profile
trase nebo ho Profile
vybere, MsalGuard
vyzve uživatele, aby se před zobrazením Profile
stránky ověřil přes automaticky otevírané okno nebo přesměrování.
MsalGuard
je třída pohodlí, kterou můžete použít ke zlepšení uživatelského prostředí, ale nemělo by se spoléhat na zabezpečení. Útočníci můžou potenciálně obejít ochranu na straně klienta a měli byste zajistit, aby server nevrátil žádná data, ke kterým by neměl uživatel přistupovat.
MsalGuard
Přidejte třídu jako zprostředkovatele v aplikaci v src/app/app.module.ts a přidejte konfigurace proMsalGuard
. Rozsahy potřebné pro získání tokenů lze později poskytnout v nástrojiauthRequest
a typ interakce pro Guard lze nastavit naRedirect
neboPopup
. Váš kód by měl vypadat takto: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 {}
MsalGuard
Nastavte trasy, které chcete chránit v src, aplikaci nebo 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 {}
Upravte volání přihlášení v src/app/app.component.ts tak, aby se zohlednila
authRequest
sada v konfiguracích ochrany. Váš kód by teď měl vypadat takto: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(); } }
Získání tokenu
Průsečík Angular
MSAL Angular poskytuje Interceptor
třídu, která automaticky získává tokeny pro odchozí požadavky, které používají klienta Angular http
ke známým chráněným prostředkům.
Interceptor
Přidejte třídu jako zprostředkovatele do aplikace v src/app/app.module.ts s jeho konfiguracemi. Váš kód by teď měl vypadat takto: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 {}
Chráněné prostředky jsou poskytovány jako
protectedResourceMap
. Adresy URL, které zadáte v kolekciprotectedResourceMap
, rozlišují malá a velká písmena. Pro každý prostředek přidejte obory, o které se žádá, aby se vrátily v přístupovém tokenu.Příklad:
["user.read"]
pro Microsoft Graph["<Application ID URL>/scope"]
pro vlastní webová rozhraní API (to znamenáapi://<Application ID>/access_as_user
)
Upravte hodnoty v následujícím
protectedResourceMap
popisu:Enter_the_Graph_Endpoint_Here
je instance rozhraní Microsoft Graph API, se kterým by aplikace měla komunikovat. V případě globálního koncového bodu rozhraní Microsoft Graph API nahraďte tento řetězec řetězcemhttps://graph.microsoft.com
. Koncové body v národních cloudových nasazeních najdete v dokumentaci k Microsoft Graphu v národních cloudových nasazeních .
Nahraďte kód v src/app/profile/profile.component.ts k načtení profilu uživatele požadavkem HTTP a nahraďte
GRAPH_ENDPOINT
ho koncovým bodem Microsoft Graphu: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; }); } }
Nahraďte uživatelské rozhraní v src/app/profile/profile.component.html , aby se zobrazily informace o profilu:
<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>
Odhlásit se
Aktualizujte kód v src/app/app.component.html tak, aby podmíněně zobrazoval
Logout
tlačítko:<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>
Odhlášení pomocí přesměrování
Aktualizujte kód v src/app/app.component.ts , aby se uživatel odhlasil pomocí přesměrování:
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(); } }
Odhlášení pomocí automaticky otevíraných oken
Aktualizujte kód v src/app/app.component.ts a odhlaste uživatele pomocí automaticky otevíraných oken:
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(); } }
Testování kódu
Spusťte webový server tak, aby naslouchal portu spuštěním následujících příkazů na příkazovém řádku ze složky aplikace:
npm install npm start
V prohlížeči zadejte
http://localhost:4200
a měla by se zobrazit stránka, která vypadá takto.Výběrem možnosti Přijmout udělte aplikaci oprávnění k vašemu profilu. K tomu dojde poprvé, když se začnete přihlašovat.
Po vyjádření souhlasu se zobrazí následující: Pokud souhlasíte s požadovanými oprávněními, webová aplikace zobrazí úspěšnou přihlašovací stránku.
Výběrem možnosti Profil zobrazíte informace o profilu uživatele vrácené v odpovědi z volání rozhraní Microsoft Graph API:
Přidání oborů a delegovaných oprávnění
Rozhraní Microsoft Graph API vyžaduje obor User.Read ke čtení profilu uživatele. Obor User.Read se automaticky přidá do každé registrace aplikace. Jiná rozhraní API pro Microsoft Graph a vlastní rozhraní API pro váš back-endový server můžou vyžadovat další obory. Rozhraní Microsoft Graph API například vyžaduje obor Mail.Read , aby bylo možné zobrazit seznam e-mailů uživatele.
Když přidáváte obory, můžou se uživatelům zobrazit výzva k poskytnutí dodatečného souhlasu s přidanými obory.
Poznámka:
Když zvýšíte počet oborů, může se uživateli zobrazit výzva k zadání dalších souhlasů.
Nápověda a podpora
Pokud potřebujete pomoc, chcete nahlásit problém nebo se chcete dozvědět o možnostech podpory, přečtěte si nápovědu a podporu pro vývojáře.
Další kroky
- Přečtěte si další informace o vytvoření jednostránkové aplikace React (SPA), která přihlašuje uživatele v následující vícedílné sérii kurzů.
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro