Oktatóanyag: Jelentkezzen be a felhasználókba, és hívja meg a Microsoft Graph API-t egy Angular egyoldalas alkalmazásból (SPA) auth code flow használatával
Ebben az oktatóanyagban egy Angular egyoldalas alkalmazást (SPA) fog létrehozni, amely bejelentkezik a felhasználókba, és meghívja a Microsoft Graph API-t a PKCE engedélyezési kódfolyamatával. A buildelt spa a Microsoft Authentication Library (MSAL) használatával használja az Angular v2-hez.
Ebben az oktatóanyagban:
- Az alkalmazás regisztrálása a Microsoft Entra Felügyeleti központban
- Angular-projekt létrehozása a
npm
- Kód hozzáadása a felhasználói bejelentkezés és kijelentkezés támogatásához
- Kód hozzáadása a Microsoft Graph API meghívásához
- Az alkalmazás tesztelése
Az MSAL Angular v2 az MSAL Angular v1-en javul azáltal, hogy az implicit engedélyezési folyamat helyett támogatja az engedélyezési kód folyamatát a böngészőben. Az MSAL Angular v2 nem támogatja az implicit folyamatot.
Előfeltételek
- Node.js helyi webkiszolgáló futtatásához.
- Visual Studio Code vagy más szerkesztő a projektfájlok módosításához.
A mintaalkalmazás működése
Az oktatóanyagban létrehozott mintaalkalmazás lehetővé teszi, hogy az Angular SPA lekérdezhesse a Microsoft Graph API-t vagy egy webes API-t, amely elfogadja a Microsoft Identitásplatform által kibocsátott jogkivonatokat. A Microsoft Authentication Library -t (MSAL) használja az Angular v2-hez, amely a MSAL.js v2-kódtár burkolója. Az MSAL Angular lehetővé teszi, hogy az Angular 9+-alkalmazások microsoft Entra-azonosítóval hitelesítsék a nagyvállalati felhasználókat, valamint a Microsoft-fiókokkal és közösségi identitásokkal rendelkező felhasználókat, például a Facebookot, a Google-t és a LinkedIn-t. A kódtár lehetővé teszi az alkalmazások számára, hogy hozzáférjenek a Microsoft felhőszolgáltatásaihoz és a Microsoft Graphhoz.
Ebben az esetben a felhasználó bejelentkezése után a rendszer hozzáférési jogkivonatot kér, és hozzáadja a HTTP-kérésekhez az engedélyezési fejlécen keresztül. A jogkivonatok beszerzését és megújítását az MSAL kezeli.
Kódtárak
Ez az oktatóanyag a következő kódtárakat használja:
Könyvtár | Leírás |
---|---|
MSAL Angular | Microsoft Authentication Library for JavaScript Angular Wrapper |
MSAL böngésző | Microsoft Authentication Library for JavaScript v2 böngészőcsomag |
Az összes MSAL.js kódtár forráskódját megtalálhatja a microsoft-authentication-library-for-js
GitHub adattárában.
A kész kódminta lekérése
Inkább az oktatóanyaghoz tartozó befejezett mintaprojektet szeretné letölteni? Az ms-identity-javascript-angular-spa klónozása
git clone https://github.com/Azure-Samples/ms-identity-javascript-angular-spa.git
Az oktatóanyag folytatásához és az alkalmazás önálló létrehozásához lépjen tovább a következő szakaszra, az alkalmazás regisztrálása és az azonosítók rögzítése.
Az alkalmazás és a rekordazonosítók regisztrálása
Tipp.
A cikkben szereplő lépések a portáltól függően kissé eltérhetnek.
A regisztráció befejezéséhez adja meg az alkalmazás nevét, adja meg a támogatott fióktípusokat, és adjon hozzá egy átirányítási URI-t. A regisztrációt követően az Alkalmazás áttekintése panel megjeleníti az alkalmazás forráskódjában szükséges azonosítókat.
- Jelentkezzen be a Microsoft Entra felügyeleti központba legalább alkalmazásfejlesztőként.
- Ha több bérlőhöz is hozzáfér, a felső menü Gépház ikonjávalválthat arra a bérlőre, amelyben regisztrálni szeretné az alkalmazást a Könyvtárak + előfizetések menüből.
- Keresse meg az identitásalkalmazásokat>> Alkalmazásregisztrációk.
- Új regisztráció kiválasztása.
- Adja meg az alkalmazás nevét, például Angular-SPA-auth-code.
- Támogatott fióktípusok esetén csak ebben a szervezeti címtárban válassza a Fiókok lehetőséget. A különböző fióktípusokkal kapcsolatos információkért válassza a Súgó kiválasztása lehetőséget.
- Az Átirányítási URI (nem kötelező) területen a legördülő menüben válassza az Egyoldalas alkalmazás (SPA) lehetőséget, és írja be
http://localhost:4200
a szövegmezőbe. - Válassza ki a pénztárgépet.
- A regisztráció befejezésekor megjelenik az alkalmazás Áttekintés panelje. Jegyezze fel a címtár (bérlő) azonosítóját és az alkalmazás forráskódjában használandó alkalmazás-(ügyfél-) azonosítót .
Projekt létrehozása
Nyissa meg a Visual Studio Code-ot, és válassza a Fájl>megnyitása mappa... lehetőséget. Keresse meg és válassza ki azt a helyet, ahol létre szeretné hozni a projektet.
Nyisson meg egy új terminált az Új terminál terminál> kiválasztásával.
- Előfordulhat, hogy termináltípusokat kell váltania. Kattintson a terminál ikonja melletti + lefelé mutató nyílra, és válassza a Parancssor lehetőséget.
Futtassa az alábbi parancsokat egy új Angular-projekt létrehozásához a következő néven
msal-angular-tutorial
, telepítse az Angular Material összetevőtárakat, az MSAL Browsert, az MSAL Angulart, és hozzon létre otthoni és profilösszetevőket.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
Az alkalmazás konfigurálása és az alapszintű felhasználói felület szerkesztése
Nyissa meg az src/app/app.module.ts. Az
MsalModule
állandóvalisIE
együtt hozzáadandó ésMsalInterceptor
hozzáadandóimports
. Az anyagmodulokat is hozzáadja. Cserélje le a fájl teljes tartalmát a következő kódrészletre: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 {}
Cserélje le a következő értékeket a Microsoft Entra felügyeleti központból beszerzett értékekre. Az elérhető konfigurálható lehetőségekről további információt az ügyfélalkalmazások inicializálása című témakörben talál.
clientId
- Az alkalmazás azonosítója, más néven az ügyfél. Cserélje leEnter_the_Application_Id_Here
az alkalmazás (ügyfél) azonosítójának értékét, amelyet korábban a regisztrált alkalmazás áttekintő oldaláról rögzítettek.authority
- Ez két részből áll:- A példány a felhőszolgáltató végpontja. A fő vagy globális Azure-felhőhöz írja be a következőt
https://login.microsoftonline.com
: . Ellenőrizze a különböző elérhető végpontokat a nemzeti felhőkben. - A bérlőazonosító annak a bérlőnek az azonosítója, amelyben az alkalmazás regisztrálva van. Cserélje le a
_Enter_the_Tenant_Info_Here
címtár (bérlő) azonosítójának értékét, amelyet korábban rögzítettek a regisztrált alkalmazás áttekintési oldaláról.
- A példány a felhőszolgáltató végpontja. A fő vagy globális Azure-felhőhöz írja be a következőt
redirectUri
- az a hely, ahol az engedélyezési kiszolgáló elküldi a felhasználót az alkalmazás sikeres engedélyezése után, és megadta az engedélyezési kódot vagy hozzáférési jogkivonatot. Cserélje le aEnter_the_Redirect_Uri_Here
elemet ahttp://localhost:4200
kérdésre.
Nyissa meg az src/app/app-routing.module.ts fájlt, és adjon hozzá útvonalakat az otthoni és profilösszetevőkhöz. Cserélje le a fájl teljes tartalmát a következő kódrészletre:
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 {}
Nyissa meg src/app/app.component.html , és cserélje le a meglévő kódot a következőre:
<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>
Nyissa meg az src/style.css a CSS definiálásához:
@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%; }
Nyissa meg az src/app/app.component.css fájlt a CSS-stílus alkalmazáshoz való hozzáadásához:
.toolbar-spacer { flex: 1 1 auto; } a.title { color: white; }
Bejelentkezés előugró ablakokkal
Nyissa meg az src/app/app.component.ts fájlt, és cserélje le a fájl tartalmát a következőre, hogy előugró ablakkal jelentkezzen be egy felhasználóba:
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; } }
Bejelentkezés átirányításokkal
Frissítse az src/app/app.module.ts-t a rendszerindításhoz.
MsalRedirectComponent
Ez egy dedikált átirányítási összetevő, amely kezeli az átirányításokat. Módosítsa az importálást ésAppComponent
aMsalModule
rendszerindítást a következőhöz hasonlóra:... import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import ... bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here ...
Nyissa meg src/index.html , és cserélje le a fájl teljes tartalmát a következő kódrészletre, amely hozzáadja a
<app-redirect>
választót:<!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>
Nyissa meg az src/app/app.component.ts alkalmazást, és cserélje le a kódot a következőre, hogy teljes keretes átirányítással jelentkezzen be egy felhasználóba:
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; } }
Lépjen az src/app/home/home.component.ts lapra, és cserélje le a fájl teljes tartalmát az alábbi kódrészletre az
LOGIN_SUCCESS
eseményre való feliratkozáshoz: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); }); } }
Feltételes renderelés
Annak érdekében, hogy bizonyos felhasználói felületeket (felhasználói felületet) csak hitelesített felhasználók számára jelenítsen meg, az összetevőknek elő kell fizetniük arra, MsalBroadcastService
hogy a felhasználók bejelentkezve vannak-e, és hogy az interakció befejeződött-e.
Adja hozzá a
MsalBroadcastService
to src/app/app.component.ts , és iratkozzon fel ainProgress$
megfigyelhetőre, hogy ellenőrizze, hogy az interakció befejeződött-e, és a felhasználói felület megjelenítése előtt be van-e jelentkezve egy fiók. A kódnak így kell kinéznie: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(); } }
Frissítse az src/app/home/home.component.ts kódját, hogy a felhasználói felület frissítése előtt ellenőrizze, hogy befejeződik-e az interakció. A kódnak így kell kinéznie:
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; } }
Cserélje le a kódot a src/app/home/home.component.html a következő feltételes megjelenítésre:
<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>
Az Angular Guard implementálása
Az MsalGuard
osztály az útvonalak védelmére használható, és hitelesítést igényel a védett útvonal elérése előtt. Az alábbi lépések hozzáadják az MsalGuard
Profile
útvonalat. Profile
Az útvonal védelme azt jelenti, hogy még akkor is, ha egy felhasználó nem a gomb használatával jelentkezik beLogin
, ha megpróbál hozzáférni az Profile
útvonalhoz, vagy kiválasztja a Profile
gombot, a MsalGuard
rendszer arra kéri a felhasználót, hogy a lap megjelenítése előtt hitelesítsen Profile
előugró vagy átirányítási funkcióval.
MsalGuard
egy kényelmi osztály, a felhasználói élmény javítása érdekében, de nem szabad a biztonságra támaszkodni. A támadók potenciálisan megkerülhetik az ügyféloldali őröket, és győződjön meg arról, hogy a kiszolgáló nem ad vissza olyan adatokat, amelyekhez a felhasználónak nem kellene hozzáférnie.
Adja hozzá az
MsalGuard
osztályt szolgáltatóként az alkalmazásban az src/app/app.module.ts fájlban, és adja hozzá a konfigurációkat aMsalGuard
. A jogkivonatok későbbi beszerzéséhez szükséges hatókörök megadhatók aauthRequest
őrségben, és a Guard interakcióinak típusa beállítható vagyPopup
beállíthatóRedirect
. A kódnak a következőképpen kell kinéznie: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 {}
Állítsa be a
MsalGuard
védeni kívánt útvonalakat az 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 {}
Állítsa be az src/app/app.component.ts bejelentkezési hívásait, hogy figyelembe vegye az
authRequest
őr konfigurációinak készletét. A kódnak most az alábbihoz hasonlóan kell kinéznie: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(); } }
Jogkivonat beszerzése
Angular Interceptor
Az MSAL Angular egy osztályt Interceptor
biztosít, amely automatikusan jogkivonatokat szerez be az Angular-ügyfelet http
ismert védett erőforrásokhoz használó kimenő kérésekhez.
Adja hozzá az
Interceptor
osztályt szolgáltatóként az alkalmazáshoz az src/app/app.module.ts, annak konfigurációival együtt. A kódnak most az alábbihoz hasonlóan kell kinéznie: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 {}
A védett erőforrásokat a rendszer a
protectedResourceMap
. A gyűjteményben megadott URL-címek megkülönböztetik aprotectedResourceMap
kis- és nagybetűket. Minden erőforráshoz adjon hozzá a hozzáférési jogkivonatban visszaadandó hatóköröket.Példa:
["user.read"]
Microsoft Graph esetén["<Application ID URL>/scope"]
egyéni webes API-khoz (azazapi://<Application ID>/access_as_user
)
Módosítsa az itt leírt értékeket
protectedResourceMap
:Enter_the_Graph_Endpoint_Here
a Microsoft Graph API azon példánya, amellyel az alkalmazásnak kommunikálnia kell. A globális Microsoft Graph API-végpont esetében cserélje le ezt a sztringet a következőrehttps://graph.microsoft.com
: . Az országos felhőbeli üzemelő példányok végpontjait a Microsoft Graph dokumentációjában találja.
Cserélje le az src/app/profile/profile.component.ts kódot egy felhasználó profiljának HTTP-kérésre való lekéréséhez, és cserélje le a
GRAPH_ENDPOINT
Microsoft Graph-végpontra: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; }); } }
Cserélje le a felhasználói felületet a src/app/profile/profile.component.html a profiladatok megjelenítéséhez:
<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>
Kijelentkezés
Frissítse a kódot a src/app/app.component.html egy gomb feltételes megjelenítéséhez
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>
Kijelentkezés átirányításokkal
Frissítse az src/app/app.component.ts kódját a felhasználó átirányítások használatával történő kijelentkezéséhez:
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(); } }
Kijelentkezés előugró ablakokkal
Frissítse az src/app/app.component.ts kódját, hogy előugró ablakokkal kijelentkeztethesse a felhasználót:
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(); } }
A kód tesztelése
Indítsa el a webkiszolgálót a port figyeléséhez az alábbi parancsok futtatásával egy parancssori parancssorban az alkalmazásmappából:
npm install npm start
A böngészőben írja be az értéket
http://localhost:4200
, és az alábbihoz hasonló lapot kell látnia.Válassza az Elfogadás lehetőséget, ha engedélyt szeretne adni az alkalmazásnak a profiljához. Ez akkor történik meg, amikor először kezd bejelentkezni.
A hozzájárulást követően a következő Ha ön hozzájárul a kért engedélyekhez, a webalkalmazás egy sikeres bejelentkezési oldalt jelenít meg.
Válassza a Profil lehetőséget a Microsoft Graph API-nak küldött hívás válaszában visszaadott felhasználói profiladatok megtekintéséhez:
Hatókörök és delegált engedélyek hozzáadása
A Microsoft Graph API megköveteli, hogy a User.Read hatókör beolvassa egy felhasználó profilját. A User.Read hatókör automatikusan hozzáadódik minden alkalmazásregisztrációhoz. A Microsoft Graph egyéb API-jai és a háttérkiszolgálóhoz tartozó egyéni API-k más hatóköröket igényelhetnek. A Microsoft Graph API-nak például a Mail.Read hatókörre van szüksége a felhasználó e-mailjeinek listázásához.
Hatókörök hozzáadásakor előfordulhat, hogy a felhasználók további hozzájárulás megadását kérik a hozzáadott hatókörökhöz.
Feljegyzés
Előfordulhat, hogy a felhasználó további hozzájárulást kér a hatókörök számának növelésekor.
Súgó és támogatás
Ha segítségre van szüksége, szeretne jelentést készíteni egy problémáról, vagy szeretne többet megtudni a támogatási lehetőségekről, olvassa el a súgót és a fejlesztők támogatását.
Következő lépések
- További információ egy React egyoldalas alkalmazás (SPA) létrehozásával, amely bejelentkezik a felhasználókba az alábbi többrészes oktatóanyag-sorozatban.