Självstudie: Logga in användare och anropa Microsoft Graph API från ett Angular-ensidesprogram (SPA) med hjälp av autentiseringskodflöde

I den här självstudien skapar du ett Angular-ensidesprogram (SPA) som loggar in användare och anropar Microsoft Graph API med hjälp av auktoriseringskodflödet med PKCE. Det SPA som du skapar använder Microsoft Authentication Library (MSAL) för Angular v2.

I den här självstudien:

  • Registrera programmet i administrationscentret för Microsoft Entra
  • Skapa ett Angular-projekt med npm
  • Lägga till kod för att stödja användarinloggning och utloggning
  • Lägga till kod för att anropa Microsoft Graph API
  • Testa appen

MSAL Angular v2 förbättrar MSAL Angular v1 genom att stödja auktoriseringskodflödet i webbläsaren i stället för det implicita beviljandeflödet. MSAL Angular v2 stöder INTE det implicita flödet.

Förutsättningar

  • Node.js för att köra en lokal webbserver.
  • Visual Studio Code eller annan redigerare för att ändra projektfiler.

Så här fungerar exempelappen

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

Exempelprogrammet som skapades i den här självstudien gör att ett Angular SPA kan köra frågor mot Microsoft Graph API eller ett webb-API som accepterar token som utfärdats av Microsofts identitetsplattform. Den använder Microsoft Authentication Library (MSAL) för Angular v2, en omslutning av MSAL.js v2-biblioteket. MSAL Angular gör det möjligt för Angular 9+-program att autentisera företagsanvändare med hjälp av Microsoft Entra-ID, och även användare med Microsoft-konton och sociala identiteter som Facebook, Google och LinkedIn. Biblioteket gör det också möjligt för program att få åtkomst till Microsofts molntjänster och Microsoft Graph.

I det här scenariot, efter att en användare har loggat in, begärs en åtkomsttoken och läggs till i HTTP-begäranden via auktoriseringshuvudet. Anskaffning och förnyelse av token hanteras av MSAL.

Bibliotek

I den här självstudien används följande bibliotek:

Bibliotek beskrivning
MSAL Angular Microsoft Authentication Library for JavaScript Angular Wrapper
MSAL-webbläsare Microsoft Authentication Library for JavaScript v2-webbläsarpaket

Du hittar källkoden för alla MSAL.js bibliotek på microsoft-authentication-library-for-js lagringsplatsen på GitHub.

Hämta det färdiga kodexemplet

Föredrar du att ladda ned det slutförda exempelprojektet för den här självstudien i stället? Klona ms-identity-javascript-angular-spa

git clone https://github.com/Azure-Samples/ms-identity-javascript-angular-spa.git

Om du vill fortsätta med självstudien och skapa programmet själv går du vidare till nästa avsnitt, Registrerar programmet och registrerar identifierare.

Registrera program- och postidentifierare

Dricks

Stegen i den här artikeln kan variera något beroende på vilken portal du börjar från.

För att slutföra registreringen anger du ett namn för programmet, anger vilka kontotyper som stöds och lägger till en omdirigerings-URI. När programmets översiktsfönster har registrerats visas de identifierare som behövs i programmets källkod.

  1. Logga in på administrationscentret för Microsoft Entra som minst programutvecklare.
  2. Om du har åtkomst till flera klienter använder du ikonen Inställningar på den översta menyn för att växla till den klientorganisation där du vill registrera programmet från menyn Kataloger + prenumerationer.
  3. Bläddra till Identitetsprogram>> Appregistreringar.
  4. Välj Ny registrering.
  5. Ange ett namn för programmet, till exempel Angular-SPA-auth-code.
  6. För Kontotyper som stöds väljer du Endast konton i den här organisationskatalogen. Om du vill ha information om olika kontotyper väljer du alternativet Hjälp mig .
  7. Under Omdirigerings-URI (valfritt) använder du den nedrullningsbara menyn för att välja Enkelsidigt program (SPA) och ange http://localhost:4200 i textrutan.
  8. Välj Registrera.
  9. Programmets översiktsfönster visas när registreringen är klar. Registrera katalog-ID:t (klient)-ID:t och program-ID:t (klient) som ska användas i programmets källkod.

Skapa projektet

  1. Öppna Visual Studio Code, välj Arkiv>Öppna mapp.... Navigera till och välj den plats där projektet ska skapas.

  2. Öppna en ny terminal genom att välja Terminal>Ny terminal.

    1. Du kan behöva byta terminaltyper. Välj nedåtpilen + bredvid ikonen i terminalen och välj Kommandotolken.
  3. Kör följande kommandon för att skapa ett nytt Angular-projekt med namnet msal-angular-tutorial, installera Komponentbibliotek för Angular Material, MSAL Browser, MSAL Angular och generera hem- och profilkomponenter.

    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
    

Konfigurera programmet och redigera basgränssnittet

  1. Öppna src/app/app.module.ts. Och MsalModuleMsalInterceptor måste läggas till imports tillsammans med konstanten isIE . Du kommer också att lägga till materialmodulerna. Ersätt hela innehållet i filen med följande kodfragment:

    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. Ersätt följande värden med de värden som hämtas från administrationscentret för Microsoft Entra. Mer information om tillgängliga konfigurerbara alternativ finns i Initiera klientprogram.

    • clientId - Identifieraren för programmet, även kallad klienten. Ersätt Enter_the_Application_Id_Here med det program-ID-värde (klient) som registrerades tidigare från översiktssidan för det registrerade programmet.
    • authority - Detta består av två delar:
      • Instansen är slutpunkten för molnleverantören. För huvudmolnet eller det globala Azure-molnet anger du https://login.microsoftonline.com. Kontrollera med de olika tillgängliga slutpunkterna i nationella moln.
      • Klientorganisations-ID:t är identifieraren för den klientorganisation där programmet är registrerat. _Enter_the_Tenant_Info_Here Ersätt med det katalog-ID-värde (klientorganisation) som registrerades tidigare från översiktssidan för det registrerade programmet.
    • redirectUri – den plats där auktoriseringsservern skickar användaren när appen har godkänts och beviljats en auktoriseringskod eller åtkomsttoken. Ersätt Enter_the_Redirect_Uri_Here med http://localhost:4200
  3. Öppna src/app/app-routing.module.ts och lägg till vägar till hem - och profilkomponenterna . Ersätt hela innehållet i filen med följande kodfragment:

    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. Öppna src/app/app.component.html och ersätt den befintliga koden med följande:

    <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. Öppna src/style.css för att definiera 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%;
    }
    
  6. Öppna src/app/app.component.css för att lägga till CSS-formatering i programmet:

    .toolbar-spacer {
      flex: 1 1 auto;
    }
    
    a.title {
      color: white;
    }
    

Logga in med popup-fönster

  1. Öppna src/app/app.component.ts och ersätt innehållet i filen med följande för att logga in en användare med ett popup-fönster:

    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;
      }
    }
    

Logga in med omdirigeringar

  1. Uppdatera src/app/app.module.ts för att starta MsalRedirectComponent. Det här är en dedikerad omdirigeringskomponent som hanterar omdirigeringar. Ändra import och MsalModuleAppComponent bootstrap så att de ser ut ungefär så här:

    ...
    import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import
    ...
      bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here
    ...
    
  2. Öppna src/index.html och ersätt hela innehållet i filen med följande kodfragment, som lägger till väljaren <app-redirect> :

    <!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. Öppna src/app/app.component.ts och ersätt koden med följande för att logga in en användare med en fullständig omdirigering:

    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. Gå till src/app/home/home.component.ts och ersätt hela innehållet i filen med följande kodfragment för att LOGIN_SUCCESS prenumerera på händelsen:

    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);
          });
      }
    }
    

Villkorsstyrd återgivning

För att endast kunna återge vissa användargränssnitt (användargränssnitt) för autentiserade MsalBroadcastService användare måste komponenterna prenumerera på för att se om användarna har loggats in och interaktionen har slutförts.

  1. MsalBroadcastService Lägg till i src/app/app.component.ts och prenumerera på det observerbara för att kontrollera om interaktionen inProgress$ är klar och ett konto loggas in innan användargränssnittet återges. Koden bör nu se ut så här:

    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. Uppdatera koden i src/app/home/home.component.ts för att även kontrollera om interaktionen ska slutföras innan användargränssnittet uppdateras. Koden bör nu se ut så här:

    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. Ersätt koden i src/app/home/home.component.html med följande villkorsstyrda skärmar:

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

Implementera Angular Guard

Klassen MsalGuard är en som du kan använda för att skydda vägar och kräva autentisering innan du kommer åt den skyddade vägen. Följande steg lägger till i MsalGuardProfile vägen. Profile Att skydda vägen innebär att även om en användare inte loggar in med Login knappen uppmanas användaren att autentisera MsalGuard via popup-fönster eller omdirigering innan sidan Profile visas om de försöker komma åt Profile vägen eller välja Profile knappen.

MsalGuard är en bekvämlighetsklass som du kan använda för att förbättra användarupplevelsen, men den bör inte användas för säkerhet. Angripare kan potentiellt komma runt skydd på klientsidan och du bör se till att servern inte returnerar några data som användaren inte ska komma åt.

  1. MsalGuard Lägg till klassen som leverantör i ditt program i src/app/app.module.ts och lägg till konfigurationerna för MsalGuard. Omfång som behövs för att hämta token senare kan anges i authRequest, och typen av interaktion för Guard kan anges till Redirect eller Popup. Koden bör se ut så här:

    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. MsalGuard Ange på de vägar som du vill skydda i 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. Justera inloggningsanropen i src/app/app.component.ts för att ta authRequest hänsyn till uppsättningen i skyddskonfigurationerna. Koden bör nu se ut så här:

    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();
      }
    }
    

Hämta en token

Angular Interceptor

MSAL Angular tillhandahåller en Interceptor klass som automatiskt hämtar token för utgående begäranden som använder Angular-klienten http till kända skyddade resurser.

  1. Interceptor Lägg till klassen som leverantör i ditt program i src/app/app.module.ts med dess konfigurationer. Koden bör nu se ut så här:

    import { BrowserModule } from "@angular/platform-browser";
    import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
    import { NgModule } from "@angular/core";
    import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http"; // Import
    
    import { MatButtonModule } from "@angular/material/button";
    import { MatToolbarModule } from "@angular/material/toolbar";
    import { MatListModule } from "@angular/material/list";
    
    import { AppRoutingModule } from "./app-routing.module";
    import { AppComponent } from "./app.component";
    import { HomeComponent } from "./home/home.component";
    import { ProfileComponent } from "./profile/profile.component";
    
    import {
      MsalModule,
      MsalRedirectComponent,
      MsalGuard,
      MsalInterceptor,
    } from "@azure/msal-angular"; // Import MsalInterceptor
    import {
      InteractionType,
      PublicClientApplication,
    } from "@azure/msal-browser";
    
    const isIE =
      window.navigator.userAgent.indexOf("MSIE ") > -1 ||
      window.navigator.userAgent.indexOf("Trident/") > -1;
    
    @NgModule({
      declarations: [AppComponent, HomeComponent, ProfileComponent],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        MatButtonModule,
        MatToolbarModule,
        MatListModule,
        HttpClientModule,
        MsalModule.forRoot(
          new PublicClientApplication({
            auth: {
              clientId: "Enter_the_Application_Id_Here",
              authority:
                "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here",
              redirectUri: "Enter_the_Redirect_Uri_Here",
            },
            cache: {
              cacheLocation: "localStorage",
              storeAuthStateInCookie: isIE,
            },
          }),
          {
            interactionType: InteractionType.Redirect,
            authRequest: {
              scopes: ["user.read"],
            },
          },
          {
            interactionType: InteractionType.Redirect, // MSAL Interceptor Configuration
            protectedResourceMap: new Map([
              ["Enter_the_Graph_Endpoint_Here/v1.0/me", ["user.read"]],
            ]),
          }
        ),
      ],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: MsalInterceptor,
          multi: true,
        },
        MsalGuard,
      ],
      bootstrap: [AppComponent, MsalRedirectComponent],
    })
    export class AppModule {}
    

    De skyddade resurserna tillhandahålls som en protectedResourceMap. Url:erna som du anger i protectedResourceMap samlingen är skiftlägeskänsliga. För varje resurs lägger du till omfång som begärs att returneras i åtkomsttoken.

    Till exempel:

    • ["user.read"] för Microsoft Graph
    • ["<Application ID URL>/scope"] för anpassade webb-API:er (det vill: api://<Application ID>/access_as_user)

    Ändra värdena i enligt beskrivningen protectedResourceMap här:

    • Enter_the_Graph_Endpoint_Here är instansen av Microsoft Graph API som programmet ska kommunicera med. För den globala Microsoft Graph API-slutpunkten ersätter du den här strängen med https://graph.microsoft.com. Slutpunkter i nationella molndistributioner finns i Nationella molndistributioner i Microsoft Graph-dokumentationen.
  2. Ersätt koden i src/app/profile/profile.component.ts för att hämta en användares profil med en HTTP-begäran och ersätt GRAPH_ENDPOINT med Microsoft Graph-slutpunkten:

    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. Ersätt användargränssnittet i src/app/profile/profile.component.html för att visa profilinformation:

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

Logga ut

  1. Uppdatera koden i src/app/app.component.html för att villkorligt visa en Logout knapp:

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

Logga ut med omdirigeringar

  1. Uppdatera koden i src/app/app.component.ts för att logga ut en användare med omdirigeringar:

    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();
      }
    }
    

Logga ut med popup-fönster

  1. Uppdatera koden i src/app/app.component.ts för att logga ut en användare med popup-fönster:

    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();
      }
    }
    

Testa koden

  1. Starta webbservern för att lyssna på porten genom att köra följande kommandon i en kommandotolk från programmappen:

    npm install
    npm start
    
  2. I webbläsaren anger du http://localhost:4200, och du bör se en sida som ser ut så här.

    Web browser displaying sign-in dialog

  3. Välj Acceptera för att bevilja appen behörighet till din profil. Detta sker första gången du börjar logga in.

    Content dialog displayed in web browser

  4. Efter medgivande visar webbprogrammet en lyckad inloggningssida om du godkänner de begärda behörigheterna.

    Results of a successful sign-in in the web browser

  5. Välj Profil för att visa användarprofilinformationen som returneras i svaret från anropet till Microsoft Graph-API:et:

    Profile information from Microsoft Graph displayed in the browser

Lägga till omfång och delegerade behörigheter

Microsoft Graph-API:et kräver user.Read-omfånget för att läsa en användares profil. User.Read-omfånget läggs automatiskt till i varje appregistrering. Andra API:er för Microsoft Graph och anpassade API:er för serverdelsservern kan kräva andra omfång. Till exempel kräver Microsoft Graph API-omfånget Mail.Read för att kunna visa användarens e-post.

När du lägger till omfång kan användarna uppmanas att ge extra medgivande för de tillagda omfången.

Kommentar

Användaren kan uppmanas att ange ytterligare medgivanden när du ökar antalet omfång.

Hjälp och support

Om du behöver hjälp, vill rapportera ett problem eller vill lära dig mer om dina supportalternativ kan du läsa Hjälp och support för utvecklare.

Nästa steg

  • Läs mer genom att skapa ett React-program med en sida (SPA) som loggar in användare i följande självstudieserie i flera delar.