Tutorial: Inicie sessão em utilizadores e chame a API do Microsoft Graph a partir de uma aplicação de página única (SPA) Angular utilizando o fluxo de código de autenticação

Neste tutorial, você cria um aplicativo de página única (SPA) Angular que entra em usuários e chama a API do Microsoft Graph usando o fluxo de código de autorização com PKCE (Proof Key for Code Exchange). O SPA que você cria usa a Microsoft Authentication Library (MSAL) para Angular v2.

Neste tutorial:

  • Registar a aplicação no centro de administração do Microsoft Entra
  • Crie um projeto Angular com npm
  • Adicionar código para dar suporte ao login e logout do usuário
  • Adicionar código para chamar a API do Microsoft Graph
  • Testar a aplicação

O MSAL Angular v2 usa o fluxo de código de autorização com PKCE no navegador, melhorando o MSAL Angular v1, que usou o fluxo de concessão implícito. Recomendamos usar o fluxo de código de autorização com PKCE para aplicativos de página única (SPAs) porque é mais seguro do que o fluxo implícito. MSAL Angular v2 NÃO suporta o fluxo implícito.

Pré-requisitos

  • Node.js para executar um servidor Web local.
  • Visual Studio Code ou outro editor para modificar arquivos de projeto.

Como funciona o aplicativo de exemplo

Diagrama mostrando o fluxo de código de autorização em um aplicativo de página única

O aplicativo de exemplo criado neste tutorial permite que um SPA Angular consulte a API do Microsoft Graph ou uma API da Web que aceita tokens emitidos pela plataforma de identidade da Microsoft. Ele usa a Microsoft Authentication Library (MSAL) para Angular v2, um wrapper da biblioteca MSAL.js v2. O MSAL Angular permite que os aplicativos Angular 9+ autentiquem usuários corporativos usando o Microsoft Entra ID e também usuários com contas da Microsoft e identidades sociais como Facebook, Google e LinkedIn. A biblioteca também permite que os aplicativos tenham acesso aos serviços de nuvem da Microsoft e ao Microsoft Graph.

Nesse cenário, depois que um usuário entra, um token de acesso é solicitado e adicionado às solicitações HTTP por meio do cabeçalho de autorização. A MSAL lida com a aquisição e renovação de tokens.

Bibliotecas

Este tutorial usa as seguintes bibliotecas:

Biblioteca Description
MSAL Angular Biblioteca de autenticação da Microsoft para JavaScript Angular Wrapper
Navegador MSAL Pacote do navegador Microsoft Authentication Library for JavaScript v2

Você pode encontrar o código-fonte de todas as bibliotecas MSAL.js no microsoft-authentication-library-for-js repositório no GitHub.

Obtenha o exemplo de código concluído

Você prefere baixar o projeto de exemplo concluído para este tutorial? Clone o ms-identity-javascript-angular-spa

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

Para continuar com o tutorial e criar o aplicativo por conta própria, vá para a próxima seção, Registrar o aplicativo e registrar identificadores.

Registar a aplicação e os identificadores de registo

Gorjeta

As etapas neste artigo podem variar ligeiramente com base no portal a partir do qual você começou.

Para concluir o registro, forneça um nome ao aplicativo, especifique os tipos de conta suportados e adicione um URI de redirecionamento. Uma vez registrado, o painel Visão geral do aplicativo exibe os identificadores necessários no código-fonte do aplicativo.

  1. Entre no centro de administração do Microsoft Entra como pelo menos um desenvolvedor de aplicativos.
  2. Se você tiver acesso a vários locatários, use o ícone Configurações no menu superior para alternar para o locatário no qual deseja registrar o aplicativo no menu Diretórios + assinaturas.
  3. Navegue até Registros do aplicativo Identity>Applications>.
  4. Selecione Novo registo.
  5. Insira um Nome para o aplicativo, como Angular-SPA-auth-code.
  6. Em Tipos de conta suportados, selecione Contas somente neste diretório organizacional. Para obter informações sobre diferentes tipos de conta, selecione a opção Ajude-me a escolher .
  7. Em Redirecionar URI (opcional), use o menu suspenso para selecionar Aplicativo de página única (SPA) e insira http://localhost:4200 a caixa de texto.
  8. Selecione Registar.
  9. O painel Visão geral do aplicativo é exibido quando o registro é concluído. Registre o ID do diretório (locatário) e o ID do aplicativo (cliente) a serem usados no código-fonte do aplicativo.

Criar o seu projeto

  1. Abra o Visual Studio Code.

  2. Selecione Arquivo>Abrir Pasta.... Navegue até o local para criar seu projeto e selecione-o.

  3. Abra um novo terminal selecionando Terminal>New Terminal.

    1. Poderá ter de mudar de tipo de terminal. Selecione a seta para baixo ao lado do + ícone no terminal e selecione Prompt de comando.
  4. Execute os seguintes comandos para criar um novo projeto Angular com o nome msal-angular-tutorial, instale bibliotecas de componentes Angular Material, MSAL Browser, MSAL Angular e gere componentes home e perfil.

    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
    

Configurar o aplicativo e editar a interface do usuário base

  1. Abra src/app/app.module.ts. O MsalModule e MsalInterceptor precisa ser adicionado junto imports com o isIE constante. Você também adiciona os módulos de material. Substitua todo o conteúdo do arquivo pelo seguinte trecho:

    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. Substitua os seguintes valores pelos valores obtidos no centro de administração do Microsoft Entra. Para obter mais informações sobre as opções configuráveis disponíveis, consulte Inicializar aplicativos cliente.

    • clientId - O identificador da aplicação, também referido como o cliente. Substitua Enter_the_Application_Id_Here pelo valor de ID do aplicativo (cliente) que foi registrado anteriormente na página de visão geral do aplicativo registrado.
    • authority - Este é composto por duas partes:
      • A instância é o ponto de extremidade do provedor de nuvem. Para a nuvem principal ou global do Azure, insira https://login.microsoftonline.com. Verifique com os diferentes pontos finais disponíveis em Nuvens nacionais.
      • O ID do Locatário é o identificador do locatário onde o aplicativo está registrado. Substitua o _Enter_the_Tenant_Info_Here pelo valor de ID do diretório (locatário) que foi registrado anteriormente na página de visão geral do aplicativo registrado.
    • redirectUri - o local para onde o servidor de autorização envia o usuário depois que o aplicativo foi autorizado com sucesso e recebeu um código de autorização ou token de acesso. Substituir Enter_the_Redirect_Uri_Here por http://localhost:4200.
  3. Abra src/app/app-routing.module.ts e adicione rotas aos componentes home e profile . Substitua todo o conteúdo do arquivo pelo seguinte trecho:

    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. Abra src/app/app.component.html e substitua o código existente pelo seguinte trecho:

    <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. Abra src/style.css para definir o 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. Abra src/app/app.component.css para adicionar estilo CSS ao aplicativo:

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

Iniciar sessão com pop-ups

  1. Abra src/app/app.component.ts e substitua o conteúdo do arquivo pelo seguinte trecho para entrar em um usuário usando uma janela pop-up:

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

Entrar usando redirecionamentos

  1. Atualize src/app/app.module.ts para inicializar o MsalRedirectComponent. Este é um componente de redirecionamento dedicado, que lida com redirecionamentos. Altere a importação e AppComponent o MsalModule bootstrap para se assemelhar ao seguinte trecho:

    ...
    import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import
    ...
      bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here
    ...
    
  2. Abra src/index.html e substitua todo o conteúdo do arquivo pelo seguinte trecho, que adiciona o <app-redirect> seletor:

    <!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. Abra src/app/app.component.ts e substitua o código pelo seguinte trecho para entrar em um usuário usando um redirecionamento full-frame:

    import { MsalService } from '@azure/msal-angular';
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
    
      constructor(private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
      }
    
      login() {
        this.authService.loginRedirect();
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    }
    
  4. Abra src/app/home/home.component.ts e substitua todo o conteúdo do arquivo pelo seguinte trecho para se inscrever no LOGIN_SUCCESS evento:

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

Renderização condicional

Para garantir que determinados componentes da Interface do Usuário (UI) sejam exibidos apenas para usuários autenticados, os componentes devem assinar o MsalBroadcastService para verificar se os usuários estão conectados e se a interação está concluída.

  1. Adicione o ao src/app/app.component.ts e assine o observável para verificar se a interação está completa e se uma conta está conectada MsalBroadcastService antes de renderizar a inProgress$ interface do usuário. Seu código agora deve ter esta aparência:

    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. Atualize o código em src/app/home/home.component.ts para também verificar se a interação foi concluída antes de atualizar a interface do usuário. Seu código agora deve ter esta aparência:

    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. Substitua o código no src/app/home/home.component.html pelas seguintes exibições condicionais:

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

Implementar Guarda Angular

A MsalGuard classe é uma que você pode usar para proteger rotas e exigir autenticação antes de acessar a rota protegida. As etapas a seguir adicionam o MsalGuard à Profile rota. Proteger a Profile rota significa que, mesmo que um usuário não entre usando o Login botão, se tentar acessar a Profile rota ou selecionar o Profile botão, o usuário solicitará que MsalGuard o usuário se autentique via pop-up ou redirecionamento antes de mostrar a Profile página.

MsalGuard é uma classe de conveniência que você pode usar para melhorar a experiência do usuário, mas não deve ser confiada para segurança. Os invasores podem potencialmente contornar os protetores do lado do cliente, e você deve garantir que o servidor não retorne nenhum dado que o usuário não deva acessar.

  1. Adicione a MsalGuard classe como um provedor em seu aplicativo em src/app/app.module.ts e adicione as configurações para o MsalGuard. Os escopos necessários para adquirir tokens posteriormente podem ser fornecidos no authRequest, e o tipo de interação para o Guarda pode ser definido como Redirect ou Popup. Seu código deve se parecer com o seguinte trecho:

    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. Defina as MsalGuard rotas que deseja proteger em 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. Ajuste as chamadas de entrada em src/app/app.component.ts para levar em conta o authRequest conjunto nas configurações de guarda. Seu código agora deve se parecer com o seguinte trecho:

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

Adquirir um token

Angular Interceptor

O MSAL Angular fornece uma Interceptor classe que adquire automaticamente tokens para solicitações de saída que usam o cliente Angular http para recursos protegidos conhecidos.

  1. Adicione a Interceptor classe como um provedor ao seu aplicativo em src/app/app.module.ts, com suas configurações. Seu código agora deve se parecer com o seguinte trecho:

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

    Os recursos protegidos são fornecidos como um protectedResourceMaparquivo . As URLs fornecidas na coleção diferenciam maiúsculas protectedResourceMap de minúsculas. Para cada recurso, adicione escopos que estão sendo solicitados para serem retornados no token de acesso.

    Por exemplo:

    • ["user.read"] para o Microsoft Graph
    • ["<Application ID URL>/scope"] para APIs da Web personalizadas (ou seja, api://<Application ID>/access_as_user)

    Modifique os valores conforme protectedResourceMap descrito aqui:

    • Enter_the_Graph_Endpoint_Here é a instância da API do Microsoft Graph com a qual o aplicativo deve se comunicar. Para o ponto de extremidade global da API do Microsoft Graph, substitua essa cadeia de caracteres por https://graph.microsoft.com. Para pontos de extremidade em implantações de nuvem nacionais , consulte Implantações de nuvem nacional na documentação do Microsoft Graph.
  2. Substitua o código em src/app/profile/profile.component.ts para recuperar o perfil de um usuário por uma solicitação HTTP e substitua o GRAPH_ENDPOINT pelo ponto de extremidade do Microsoft Graph:

    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. Substitua a interface do usuário no src/app/profile/profile.component.html para exibir informações de perfil:

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

Terminar sessão

  1. Atualize o código no src/app/app.component.html para exibir condicionalmente um Logout botão:

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

Sair usando redirecionamentos

  1. Atualize o código em src/app/app.component.ts para sair de um usuário usando redirecionamentos:

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

Sair usando pop-ups

  1. Atualize o código em src/app/app.component.ts para sair de um usuário usando pop-ups:

    import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
    import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
    import { InteractionStatus, PopupRequest } from '@azure/msal-browser';
    import { Subject } from 'rxjs';
    import { filter, takeUntil } from 'rxjs/operators';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit, OnDestroy {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        if (this.msalGuardConfig.authRequest){
          this.authService.loginPopup({...this.msalGuardConfig.authRequest} as PopupRequest)
            .subscribe({
              next: (result) => {
                console.log(result);
                this.setLoginDisplay();
              },
              error: (error) => console.log(error)
            });
        } else {
          this.authService.loginPopup()
            .subscribe({
              next: (result) => {
                console.log(result);
                this.setLoginDisplay();
              },
              error: (error) => console.log(error)
            });
        }
      }
    
      logout() { // Add log out function here
        this.authService.logoutPopup({
          mainWindowRedirectUri: "/"
        });
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    

Teste o seu código

  1. Inicie o servidor Web para ouvir a porta executando os seguintes comandos em um prompt de linha de comando da pasta do aplicativo:

    npm install
    npm start
    
  2. No navegador, digite http://localhost:4200, e você verá uma página parecida com a seguinte.

    Navegador da Web exibindo a caixa de diálogo de entrada

  3. Selecione Aceitar para conceder as permissões do aplicativo ao seu perfil. Isso acontece na primeira vez que você começa a entrar.

    Caixa de diálogo Conteúdo exibida no navegador da Web

  4. Se você concordar com as permissões solicitadas, o aplicativo Web mostrará uma página de login bem-sucedida.

    Resultados de uma entrada bem-sucedida no navegador da Web

  5. Selecione Perfil para exibir as informações de perfil de usuário retornadas na resposta da chamada para a API do Microsoft Graph:

    Informações de perfil do Microsoft Graph exibidas no navegador

Adicionar escopos e permissões delegadas

A API do Microsoft Graphs requer o escopo User.Read para ler o perfil de um usuário. O escopo User.Read é adicionado automaticamente a cada registro de aplicativo. Outras APIs para o Microsoft Graph e APIs personalizadas para seu servidor back-end podem exigir outros escopos. Por exemplo, a API do Microsoft Graphs requer o escopo Mail.Read para listar o email do usuário.

À medida que você adiciona escopos, os usuários podem ser solicitados a fornecer consentimento extra para os escopos adicionados.

Nota

O usuário pode ser solicitado a fornecer consentimentos adicionais à medida que você aumenta o número de escopos.

Ajuda e suporte

Se precisar de ajuda, quiser comunicar um problema ou quiser saber mais sobre as suas opções de suporte, consulte Ajuda e suporte para programadores.

Próximos passos