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

Diagram showing the authorization code flow in a single-page application

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.

  1. Jelentkezzen be a Microsoft Entra felügyeleti központba legalább alkalmazásfejlesztőként.
  2. 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.
  3. Keresse meg az identitásalkalmazásokat>> Alkalmazásregisztrációk.
  4. Új regisztráció kiválasztása.
  5. Adja meg az alkalmazás nevét, például Angular-SPA-auth-code.
  6. 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.
  7. 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.
  8. Válassza ki a pénztárgépet.
  9. 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

  1. 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.

  2. Nyisson meg egy új terminált az Új terminál terminál> kiválasztásával.

    1. 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.
  3. 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

  1. Nyissa meg az src/app/app.module.ts. Az MsalModule állandóval isIE együtt hozzáadandó és MsalInterceptor 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 {}
    
  2. 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 le Enter_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_Herecí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.
    • 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 a Enter_the_Redirect_Uri_Here elemet a http://localhost:4200 kérdésre.
  3. 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 {}
    
  4. 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>
    
  5. 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%;
    }
    
  6. 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

  1. 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

  1. 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 és AppComponent a MsalModule 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
    ...
    
  2. 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>
    
  3. 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;
      }
    }
    
  4. 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.

  1. Adja hozzá a MsalBroadcastService to src/app/app.component.ts , és iratkozzon fel a inProgress$ 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();
      }
    }
    
  2. 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;
      }
    }
    
  3. 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 MsalGuardProfile ú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.

  1. 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 a MsalGuard. A jogkivonatok későbbi beszerzéséhez szükséges hatókörök megadhatók a authRequestőrségben, és a Guard interakcióinak típusa beállítható vagy Popupbeá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 {}
    
  2. Á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 {}
    
  3. Á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.

  1. 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 a protectedResourceMap 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 (azaz api://<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.
  2. 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;
          });
      }
    }
    
  3. 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

  1. Frissítse a kódot a src/app/app.component.html egy gomb feltételes megjelenítéséhezLogout:

    <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

  1. 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

  1. 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

  1. 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
    
  2. A böngészőben írja be az értéket http://localhost:4200, és az alábbihoz hasonló lapot kell látnia.

    Web browser displaying sign-in dialog

  3. 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.

    Content dialog displayed in web browser

  4. 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.

    Results of a successful sign-in in the web browser

  5. 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:

    Profile information from Microsoft Graph displayed in the browser

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.