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
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.
- Entre no centro de administração do Microsoft Entra como pelo menos um desenvolvedor de aplicativos.
- 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.
- Navegue até Registros do aplicativo Identity>Applications>.
- Selecione Novo registo.
- Insira um Nome para o aplicativo, como Angular-SPA-auth-code.
- 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 .
- 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. - Selecione Registar.
- 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
Abra o Visual Studio Code.
Selecione Arquivo>Abrir Pasta.... Navegue até o local para criar seu projeto e selecione-o.
Abra um novo terminal selecionando Terminal>New Terminal.
- Poderá ter de mudar de tipo de terminal. Selecione a seta para baixo ao lado do + ícone no terminal e selecione Prompt de comando.
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
Abra src/app/app.module.ts. O
MsalModule
eMsalInterceptor
precisa ser adicionado juntoimports
com oisIE
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 {}
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. SubstituaEnter_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.
- A instância é o ponto de extremidade do provedor de nuvem. Para a nuvem principal ou global do Azure, insira
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. SubstituirEnter_the_Redirect_Uri_Here
porhttp://localhost:4200
.
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 {}
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>
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%; }
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
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
Atualize src/app/app.module.ts para inicializar o
MsalRedirectComponent
. Este é um componente de redirecionamento dedicado, que lida com redirecionamentos. Altere a importação eAppComponent
oMsalModule
bootstrap para se assemelhar ao seguinte trecho:... import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import ... bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here ...
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>
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; } }
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.
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 ainProgress$
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(); } }
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; } }
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.
Adicione a
MsalGuard
classe como um provedor em seu aplicativo em src/app/app.module.ts e adicione as configurações para oMsalGuard
. Os escopos necessários para adquirir tokens posteriormente podem ser fornecidos noauthRequest
, e o tipo de interação para o Guarda pode ser definido comoRedirect
ouPopup
. 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 {}
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 {}
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.
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
protectedResourceMap
arquivo . As URLs fornecidas na coleção diferenciam maiúsculasprotectedResourceMap
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 porhttps://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.
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; }); } }
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
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
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
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
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
No navegador, digite
http://localhost:4200
, e você verá uma página parecida com a seguinte.Selecione Aceitar para conceder as permissões do aplicativo ao seu perfil. Isso acontece na primeira vez que você começa a entrar.
Se você concordar com as permissões solicitadas, o aplicativo Web mostrará uma página de login bem-sucedida.
Selecione Perfil para exibir as informações de perfil de usuário retornadas na resposta da chamada para a API do Microsoft Graph:
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
- Saiba mais criando um aplicativo de página única (SPA) React que inicia sessão nos utilizadores na seguinte série de tutoriais com várias partes.