Compartilhar via


Habilitar a autenticação em seu próprio aplicativo Angular usando o Azure Active Directory B2C

Este artigo mostra como adicionar a autenticação do Azure Active Directory B2C (Azure AD B2C) a seu próprio aplicativo Angular de página única (SPA). Saiba como integrar um aplicativo Angular com a biblioteca de autenticação do MSAL Angular.

Use este artigo com o artigo relacionado intitulado Configurar autenticação em um exemplo de aplicativo Angular de página única. Substitua o aplicativo Angular exemplo por seu próprio aplicativo Angular. Depois de concluir as etapas neste artigo, seu aplicativo aceitará as credenciais por meio do Azure AD B2C.

Pré-requisitos

Conclua as etapas no artigo Configurar autenticação em um exemplo de aplicativo Angular de página única.

Criar um projeto de aplicativo Angular

É possível usar um projeto de aplicativo Angular existente ou criar um novo. Execute os comandos a seguir para criar um novo projeto.

Os comandos:

  1. Instale a CLI do Angular usando o gerenciador de pacotes npm.
  2. Crie um espaço de trabalho Angular com um módulo de roteamento. O nome do aplicativo é msal-angular-tutorial. É possível alterá-lo para qualquer nome de aplicativo Angular válido, como contoso-car-service.
  3. Altere para a pasta de diretório do aplicativo.
npm install -g @angular/cli 
ng new msal-angular-tutorial --routing=true --style=css --strict=false
cd msal-angular-tutorial

Instalar as dependências

Para instalar as bibliotecas do MSAL Navegador e do MSAL Angular em seu aplicativo, execute os comandos a seguir no shell de comando:

npm install @azure/msal-browser @azure/msal-angular

Instale a biblioteca de componentes Angular Material (opcional, para a interface do usuário):

npm install @angular/material @angular/cdk

Adicionar os componentes de autenticação

O código de exemplo é composto pelos componentes a seguir:

Componente Tipo Descrição
auth-config.ts Constantes Esse arquivo de configuração contém informações sobre o seu provedor de identidade do Azure AD B2C e o serviço da API Web. O aplicativo Angular usa essas informações para estabelecer uma relação de confiança com o Azure AD B2C, conectar e desconectar o usuário, adquirir tokens e validá-los.
app.module.ts Módulo Angular Este componente descreve como as partes do aplicativo se encaixam. Esse é o módulo raiz que é usado para inicializar e abrir o aplicativo. Neste tutorial, você vai adicionar alguns componentes ao módulo app.module.ts e iniciar a biblioteca MSAL com o objeto de configuração MSAL.
app-routing.module.ts Módulo de roteamento Angular Este componente permite a navegação interpretando uma URL do navegador e carregando o componente correspondente. Neste tutorial, você vai adicionar alguns componentes ao módulo de roteamento e proteger os componentes com a MSAL Guard. Somente usuários autorizados podem acessar os componentes protegidos.
app.component.* Componente Angular O comando ng new criou um projeto Angular com um componente raiz. Neste tutorial, você vai alterar o componente do aplicativo para hospedar a barra de navegação superior. A barra de navegação contém vários botões, incluindo botões de logon e de saída. A classe app.component.ts lida com os eventos de logon e de saída.
home.component.* Componente Angular Neste tutorial, você vai adicionar o componente home para renderizar a página inicial para acesso anônimo. Este componente demonstra como verificar se um usuário entrou.
profile.component.* Componente Angular Neste tutorial, você vai adicionar o componente profile para saber como ler as declarações de token de ID.
webapi.component.* Componente Angular Neste tutorial, você vai adicionar o componente webapi para saber como chamar uma API Web.

Para adicionar os componentes seguintes ao seu aplicativo, execute os seguintes comandos do CLI do Angular. Os comandos generate component:

  1. Crie uma pasta para cada componente. A pasta contém os arquivos TypeScript, HTML, CSS e os arquivos de teste.
  2. Atualize os arquivos app.module.ts e app-routing.module.ts com referências aos novos componentes.
ng generate component home
ng generate component profile
ng generate component webapi

Adicionar as configurações do aplicativo

As configurações para o provedor de identidade do Azure AD B2C e a API Web são armazenadas no arquivo auth-config.ts. Na pasta src/app, crie um arquivo chamado auth-config.ts que contenha o código a seguir. Em seguida, altere as configurações conforme descrito em 3.1 Configurar o exemplo do Angular.

import { LogLevel, Configuration, BrowserCacheLocation } from '@azure/msal-browser';

const isIE = window.navigator.userAgent.indexOf("MSIE ") > -1 || window.navigator.userAgent.indexOf("Trident/") > -1;
 
export const b2cPolicies = {
     names: {
         signUpSignIn: "b2c_1_susi_reset_v2",
         editProfile: "b2c_1_edit_profile_v2"
     },
     authorities: {
         signUpSignIn: {
             authority: "https://your-tenant-name.b2clogin.com/your-tenant-name.onmicrosoft.com/b2c_1_susi_reset_v2",
         },
         editProfile: {
             authority: "https://your-tenant-name.b2clogin.com/your-tenant-name.onmicrosoft.com/b2c_1_edit_profile_v2"
         }
     },
     authorityDomain: "your-tenant-name.b2clogin.com"
 };
 
 
export const msalConfig: Configuration = {
     auth: {
         clientId: '<your-MyApp-application-ID>',
         authority: b2cPolicies.authorities.signUpSignIn.authority,
         knownAuthorities: [b2cPolicies.authorityDomain],
         redirectUri: '/', 
     },
     cache: {
         cacheLocation: BrowserCacheLocation.LocalStorage,
         storeAuthStateInCookie: isIE, 
     },
     system: {
         loggerOptions: {
            loggerCallback: (logLevel, message, containsPii) => {
                console.log(message);
             },
             logLevel: LogLevel.Verbose,
             piiLoggingEnabled: false
         }
     }
 }

export const protectedResources = {
  todoListApi: {
    endpoint: "http://localhost:5000/api/todolist",
    scopes: ["https://your-tenant-name.onmicrosoft.com/api/tasks.read"],
  },
}
export const loginRequest = {
  scopes: []
};

Inicie as bibliotecas de autenticação

Os aplicativos cliente públicos não são confiáveis para manter com segurança os segredos do aplicativo, portanto, não contêm segredos do cliente. Na pasta src/app, abra o app.module.tse faça as seguintes alterações:

  1. Importe as bibliotecas MSAL Angular e MSAL Browser.
  2. Atualize o módulo de configuração do Azure AD B2C.
  3. Importe HttpClientModule. O cliente HTTP é usado para chamar as APIs Web.
  4. Importe o interceptador HTTP Angular. A MSAL usa o Interceptor para injetar o token de portador no cabeçalho de autorização HTTP.
  5. Adicione os materiais Angular essenciais.
  6. Crie uma instância de MSAL usando um objeto de aplicativo de cliente público de várias contas. A inicialização do MSAL inclui a passagem:
    1. Do objeto de configuração para o auth-config.ts.
    2. Do objeto de configuração para a cláusula de proteção de roteamento.
    3. Do objeto de configuração para o interceptador do MSAL. A classe do interceptador adquire automaticamente tokens para solicitações de saída que usam a classe HttpClient Angular para recursos protegidos conhecidos.
  7. Configure o HTTP_INTERCEPTORS e MsalGuardprovedores do Angular .
  8. Adicione MsalRedirectComponent à inicialização do Angular.

Na pasta src/app, edite o app.module.ts e faça as modificações mostradas no trecho de código a seguir. As alterações são sinalizadas com "As alterações começam aqui" e "As alterações terminam aqui".

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

/* Changes start here. */
// Import MSAL and MSAL browser libraries. 
import { MsalGuard, MsalInterceptor, MsalModule, MsalRedirectComponent } from '@azure/msal-angular';
import { InteractionType, PublicClientApplication } from '@azure/msal-browser';

// Import the Azure AD B2C configuration 
import { msalConfig, protectedResources } from './auth-config';

// Import the Angular HTTP interceptor. 
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { ProfileComponent } from './profile/profile.component';
import { HomeComponent } from './home/home.component';
import { WebapiComponent } from './webapi/webapi.component';

// Add the essential Angular materials.
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatListModule } from '@angular/material/list';
import { MatTableModule } from '@angular/material/table';
/* Changes end here. */

@NgModule({
  declarations: [
    AppComponent,
    ProfileComponent,
    HomeComponent,
    WebapiComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    /* Changes start here. */
    // Import the following Angular materials. 
    MatButtonModule,
    MatToolbarModule,
    MatListModule,
    MatTableModule,
    // Import the HTTP client. 
    HttpClientModule,

    // Initiate the MSAL library with the MSAL configuration object
    MsalModule.forRoot(new PublicClientApplication(msalConfig),
      {
        // The routing guard configuration. 
        interactionType: InteractionType.Redirect,
        authRequest: {
          scopes: protectedResources.todoListApi.scopes
        }
      },
      {
        // MSAL interceptor configuration.
        // The protected resource mapping maps your web API with the corresponding app scopes. If your code needs to call another web API, add the URI mapping here.
        interactionType: InteractionType.Redirect,
        protectedResourceMap: new Map([
          [protectedResources.todoListApi.endpoint, protectedResources.todoListApi.scopes]
        ])
      })
    /* Changes end here. */
  ],
  providers: [
    /* Changes start here. */
    {
      provide: HTTP_INTERCEPTORS,
      useClass: MsalInterceptor,
      multi: true
    },
    MsalGuard
    /* Changes end here. */
  ],
  bootstrap: [
    AppComponent,
    /* Changes start here. */
    MsalRedirectComponent
    /* Changes end here. */
  ]
})
export class AppModule { }

Configurar rotas

Nesta seção, configure as rotas para o seu aplicativo Angular. Quando um usuário seleciona um link na página para mover-se dentro de seu aplicativo de página única ou insere uma URL na barra de endereços, as rotas mapeiam a URL para um componente Angular. A interface de roteamento angular canActivate usa o MSAL Guard para verificar se o usuário está conectado. Se o usuário não estiver conectado, o MSAL leva o usuário ao Azure AD B2C para que ele seja autenticado.

Na pasta src/app, edite o app-routing.module.ts e faça as modificações mostradas no trecho de código a seguir. As alterações são sinalizadas com "As alterações começam aqui" e "As alterações terminam aqui".

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MsalGuard } from '@azure/msal-angular';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { WebapiComponent } from './webapi/webapi.component';

const routes: Routes = [
  /* Changes start here. */
  {
    path: 'profile',
    component: ProfileComponent,
    // The profile component is protected with MSAL Guard.
    canActivate: [MsalGuard]
  },
  {
    path: 'webapi',
    component: WebapiComponent,
    // The profile component is protected with MSAL Guard.
    canActivate: [MsalGuard]
  },
  {
    // The home component allows anonymous access
    path: '',
    component: HomeComponent
  }
  /* Changes end here. */
];


@NgModule({
  /* Changes start here. */
  // Replace the following line with the next one
  //imports: [RouterModule.forRoot(routes)],
  imports: [RouterModule.forRoot(routes, {
    initialNavigation:'enabled'
  })],
  /* Changes end here. */
  exports: [RouterModule]
})
export class AppRoutingModule { }

Adicionar os botões de entrada e saída

Nesta seção, você vai adicionar os botões de entrada e saída do componente do app. Na pasta src/app, abra o app.component.tse faça as seguintes alterações:

  1. Importe os componentes obrigatórios.

  2. Altere a classe para implementar o método OnInit. O método OnInitassina o evento observável inProgress$ do MSAL MsalBroadcastService. Use esse evento para saber o status das interações do usuário, especialmente para verificar se as interações foram concluídas.

    Antes das interações com o objeto de conta MSAL, verifique se a InteractionStatuspropriedade retornaInteractionStatus.None. O evento subscribe chama o método setLoginDisplay para verificar se o usuário está autenticado.

  3. Adicione variáveis de classe.

  4. Adicione o método login que inicia o fluxo de autorização.

  5. Adicione o método logout que desconecta o usuário.

  6. Adicione o método setLoginDisplay que verifica se o usuário está autenticado.

  7. Adicione o método ngOnDestroy para limpar o evento de assinatura inProgress$.

Após as alterações, o código deve ser semelhante ao seguinte trecho de código:

import { Component, OnInit, 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']
})

/* Changes start here. */
export class AppComponent implements OnInit{
  title = 'msal-angular-tutorial';
  loginDisplay = false;
  private readonly _destroying$ = new Subject<void>();

  constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }

  ngOnInit() {

    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() { 
    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();
  }
  /* Changes end here. */
}

Na pasta src/app, edite o app.component.htmle faça as seguintes alterações:

  1. Adicione um link para o perfil e os componentes da API Web.
  2. Adicione o botão de logon com o atributo de evento de clique definido como o método login(). Esse botão só aparecerá se a variável de classe loginDisplay for false.
  3. Adicione o botão de logout com o atributo de evento de clique definido como o método logout(). Esse botão só aparecerá se a variável de classe loginDisplay for true.
  4. Adicione um elemento router-outlet .

Após as alterações, o código deve ser semelhante ao seguinte trecho de código:

<mat-toolbar color="primary">
  <a class="title" href="/">{{ title }}</a>

  <div class="toolbar-spacer"></div>

  <a mat-button [routerLink]="['profile']">Profile</a>
  <a mat-button [routerLink]="['webapi']">Web API</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">
  <router-outlet></router-outlet>
</div>

Opcionalmente, atualize o app.component.css com o seguinte trecho de CSS:

.toolbar-spacer {
    flex: 1 1 auto;
  }

  a.title {
    color: white;
  }

Manipular os redirecionamentos de aplicativo

Ao estiver usando redirecionamentos com o MSAL, deverá adicionar a diretiva app-redirect ao arquivo index.html. Na pasta src, edite o index.html conforme mostrado no trecho de código a seguir:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>MsalAngularTutorial</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>
  <!-- Changes start here -->
  <app-redirect></app-redirect>
  <!-- Changes end here -->
</body>
</html>

Definir CSS do aplicativo (opcional)

Na pasta /src, atualize o styles.css com o seguinte trecho de código do 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%; }

Dica

Neste ponto, você pode executar seu aplicativo e testar a experiência de entrada. Para executar o aplicativo, consulte a seção Executar o aplicativo Angular.

Verificar se um usuário está autenticado

O arquivo home.component demonstra como verificar se um usuário está autenticado. Na pasta src/app/home, atualize home.component.ts com o trecho de código a seguir.

O código:

  1. Assina os evento observáveis msalSubject$ e inProgress$ do MSAL MsalBroadcastService.
  2. Garante que o evento msalSubject$ grave o resultado da autenticação no console do navegador.
  3. Garante que o evento inProgress$ verifique se um usuário está autenticado. O método getAllAccounts() retorna um ou mais objetos.
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;
  }
}

Na pasta src/app/home, atualize o arquivo home.component.html com o trecho HTML a seguir. A diretiva *ngIf verifica a variável de classe loginDisplay para mostrar ou ocultar as mensagens de boas-vindas.

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

Ler as declarações de token de ID

O arquivo profile.component demonstra como acessar as declarações de token de ID do usuário. Na pasta src/app/home, atualize profile.component.ts com o trecho de código a seguir.

O código:

  1. Importa os componentes obrigatórios.
  2. Assina o evento observável inProgress$ do MSAL MsalBroadcastService. O evento carrega a conta e lê as declarações do token de ID.
  3. Garante que o método checkAndSetActiveAccount verifique e defina a conta ativa. Esta ação é comum quando o aplicativo interage com vários fluxos de usuário Azure AD B2C ou com políticas personalizadas.
  4. Certifique-se de que o método getClaims obtém as declarações de token de ID do objeto de conta MSAL ativo. Em seguida, o método adiciona as declarações à matriz dataSource. A matriz é renderizada para o usuário com a associação de modelo do componente.
import { Component, OnInit } from '@angular/core';
import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
import { EventMessage, EventType, InteractionStatus } from '@azure/msal-browser';
import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.css']
})

export class ProfileComponent implements OnInit {
  displayedColumns: string[] = ['claim', 'value'];
  dataSource: Claim[] = [];
  private readonly _destroying$ = new Subject<void>();
  
  constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }

  ngOnInit(): void {

    this.msalBroadcastService.inProgress$
      .pipe(
        filter((status: InteractionStatus) =>  status === InteractionStatus.None || status === InteractionStatus.HandleRedirect),
        takeUntil(this._destroying$)
      )
      .subscribe(() => {
        this.checkAndSetActiveAccount();
        this.getClaims(this.authService.instance.getActiveAccount()?.idTokenClaims)
      })
  }

  checkAndSetActiveAccount() {

    let activeAccount = this.authService.instance.getActiveAccount();

    if (!activeAccount && this.authService.instance.getAllAccounts().length > 0) {
      let accounts = this.authService.instance.getAllAccounts();
      this.authService.instance.setActiveAccount(accounts[0]);
    }
  }

  getClaims(claims: any) {

    let list: Claim[]  =  new Array<Claim>();

    Object.keys(claims).forEach(function(k, v){
      
      let c = new Claim()
      c.id = v;
      c.claim = k;
      c.value =  claims ? claims[k]: null;
      list.push(c);
    });
    this.dataSource = list;

  }

  ngOnDestroy(): void {
    this._destroying$.next(undefined);
    this._destroying$.complete();
  }
}

export class Claim {
  id: number;
  claim: string;
  value: string;
}

Na pasta src/app/profile, atualize profile.component.html com o trecho HTML a seguir:

<h1>ID token claims:</h1>

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">

  <!-- Claim Column -->
  <ng-container matColumnDef="claim">
    <th mat-header-cell *matHeaderCellDef> Claim </th>
    <td mat-cell *matCellDef="let element"> {{element.claim}} </td>
  </ng-container>

  <!-- Value Column -->
  <ng-container matColumnDef="value">
    <th mat-header-cell *matHeaderCellDef> Value </th>
    <td mat-cell *matCellDef="let element"> {{element.value}} </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

Chamar uma API da Web

Para chamar uma API Web de autorização baseada em token, o aplicativo precisa ter um token de acesso válido. O provedor MsalInterceptor adquire automaticamente tokens para solicitações de saída que usam a classe HttpClient Angular para recursos protegidos conhecidos.

Importante

O método de inicialização MSAL (na classe app.module.ts) mapeia recursos protegidos, como APIs Web, aos escopos de aplicativo necessários usando o objeto protectedResourceMap. Se seu código precisar chamar outra API Web, adicione o URI da API Web e o método HTTP da API Web com os escopos correspondentes ao objeto protectedResourceMap. Para saber mais, confira Mapa de recursos protegido.

Quando o objeto HttpClient chama uma API Web, o provedor MsalInterceptor executa as seguintes etapas:

  1. Adquire um token de acesso com as permissões necessárias (escopos) para o ponto de extremidade da API Web.

  2. Passa o token de acesso como um token de portador no cabeçalho de autorização da solicitação HTTP usando este formato:

    Authorization: Bearer <access-token>
    

O arquivo webapi.component demonstra como chamar a API Web. Na pasta src/app/webapi, atualize webapi.component.ts com o trecho de código a seguir.

O código:

  1. Usa a classe HttpClient Angular para chamar a API Web.
  2. Lê o elemento auth-config da classe protectedResources.todoListApi.endpoint. Esse elemento especifica o URI da API Web. Com base no URI da API Web, o interceptador MSAL adquire um token de acesso com os escopos correspondentes.
  3. Obtém o perfil da API Web e define a variável de classe profile.
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { protectedResources } from '../auth-config';

type ProfileType = {
  name?: string
};

@Component({
  selector: 'app-webapi',
  templateUrl: './webapi.component.html',
  styleUrls: ['./webapi.component.css']
})
export class WebapiComponent implements OnInit {
  todoListEndpoint: string = protectedResources.todoListApi.endpoint;
  profile!: ProfileType;

  constructor(
    private http: HttpClient
  ) { }

  ngOnInit() {
    this.getProfile();
  }

  getProfile() {
    this.http.get(this.todoListEndpoint)
      .subscribe(profile => {
        this.profile = profile;
      });
  }
}

Na pasta src/app/webapi, atualize o arquivo webapi.component.html com o trecho HTML a seguir. O modelo do componente renderiza o nome que a API Web retorna. Na parte inferior da página, o modelo renderiza o endereço da API Web.

<h1>The web API returns:</h1>
<div>
    <p><strong>Name: </strong> {{profile?.name}}</p>
</div>

<div class="footer-text">
    Web API: {{todoListEndpoint}}
</div>

Opcionalmente, atualize o arquivo webapi.component.css com o seguinte trecho de CSS:

.footer-text {
    position: absolute;
    bottom: 50px;
    color: gray;
}

Executar o aplicativo Angular

Execute o comando a seguir:

npm start

A janela de console exibe o número da porta em que o aplicativo está hospedado.

Listening on port 4200...

Dica

Como alternativa para executar o comando npm start, você pode usar o depurador do Visual Studio Code. O depurador ajuda a acelerar o loop de edição, compilação e depuração.

Acesse http://localhost:4200 no navegador para exibir o aplicativo.

Próximas etapas