Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Importante
A partir de 1º de maio de 2025, o Azure AD B2C não estará mais disponível para compra para novos clientes. Saiba mais nas nossas Perguntas Frequentes.
Este artigo mostra como adicionar a autenticação do Azure Ative Directory B2C (Azure AD B2C) ao seu próprio aplicativo de página única (SPA) Angular. Saiba como integrar um aplicativo Angular com a biblioteca de autenticação MSAL for Angular .
Use este artigo com o artigo relacionado intitulado Configurar autenticação em um aplicativo de página única Angular de exemplo. Substitua o aplicativo Angular de exemplo pelo seu próprio aplicativo Angular. Depois de concluir as etapas neste artigo, seu aplicativo aceitará entradas por meio do Azure AD B2C.
Pré-requisitos
Conclua as etapas no artigo Configurar autenticação em um aplicativo de página única Angular de exemplo .
Criar um projeto de aplicativo Angular
Você pode usar um projeto de aplicativo Angular existente ou criar um novo. Para criar um novo projeto, execute os seguintes comandos.
Os comandos:
- Instale a CLI Angular usando o gerenciador de pacotes npm.
-
Crie um espaço de trabalho Angular com um módulo de roteamento. O nome do aplicativo é
msal-angular-tutorial. Você pode alterá-lo para qualquer nome de aplicativo Angular válido, comocontoso-car-service. - Mude para a pasta do 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 MSAL Browser e MSAL Angular em seu aplicativo, execute o seguinte comando no shell de comando:
npm install @azure/msal-browser @azure/msal-angular
Instale a biblioteca de componentes Material Angular (opcional, para UI):
npm install @angular/material @angular/cdk
Adicionar os componentes de autenticação
O código de exemplo consiste nos seguintes componentes:
| Componente | Tipo | Descrição |
|---|---|---|
| auth-config.ts | Constantes | Este arquivo de configuração contém informações sobre seu provedor de identidade do Azure AD B2C e o serviço de API Web. O aplicativo Angular usa essas informações para estabelecer uma relação de confiança com o Azure AD B2C, entrar e sair do usuário, adquirir tokens e validar os tokens. |
| app.module.ts | Módulo angular | Este componente descreve como as partes do aplicativo se encaixam. Este é o módulo raiz que é usado para inicializar e abrir o aplicativo. Nesta explicação passo a passo, você adiciona alguns componentes ao módulo app.module.ts e inicia 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 um URL do navegador e carregando o componente correspondente. Nesta explicação passo a passo, você adiciona alguns componentes ao módulo de roteamento e protege os componentes com o MSAL Guard. Somente usuários autorizados podem acessar os componentes protegidos. |
| app.component.* | Componente angular | O ng new comando criou um projeto Angular com um componente raiz. Neste passo a passo, você altera 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 entrada e saída. A app.component.ts classe lida com os eventos de entrada e saída. |
| home.componente.* | Componente angular | Neste passo a passo, você adiciona o componente home para renderizar a home page para acesso anônimo. Este componente demonstra como verificar se um usuário entrou em. |
| perfil.componente.* | Componente angular | Neste passo a passo, você adiciona o componente de perfil para saber como ler as declarações de token de ID. |
| webapi.component.* | Componente angular | Neste passo a passo, você adiciona o componente webapi para aprender a chamar uma API da Web. |
Para adicionar os seguintes componentes ao seu aplicativo, execute os seguintes comandos da CLI Angular. Os generate component comandos:
- Crie uma pasta para cada componente. A pasta contém os arquivos TypeScript, HTML, CSS e de teste.
- Atualize os
app.module.tsarquivos eapp-routing.module.tscom 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 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: []
};
Iniciar as bibliotecas de autenticação
Os aplicativos cliente públicos não são confiáveis para manter segredos de aplicativos com segurança, portanto, eles não têm segredos de cliente. Na pasta src/app , abra app.module.ts e faça as seguintes alterações:
- Importe as bibliotecas MSAL Angular e MSAL Browser.
- Importe o módulo de configuração do Azure AD B2C.
- Importar
HttpClientModule. O cliente HTTP é usado para chamar APIs da Web. - Importe o intercetador HTTP do Angular. MSAL usa o intercetor para injetar o token de portador para o cabeçalho de autorização HTTP.
- Adicione os materiais angulares essenciais.
- Instancie o MSAL utilizando o objeto de aplicação cliente público para múltiplas contas. A inicialização do MSAL inclui a aprovação:
- O objeto de configuração para auth-config.ts.
- O objeto de configuração do guardião de roteamento.
- O objeto de configuração para o intercetador MSAL. A classe intercetor adquire automaticamente tokens para solicitações de saída que usam a classe Angular HttpClient para recursos protegidos conhecidos.
- Configure os provedores
HTTP_INTERCEPTORSeMsalGuardAngular. - Adicione
MsalRedirectComponentao bootstrap Angular.
Na pasta src/app, edite-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 seu aplicativo Angular. Quando um usuário seleciona um link na página para mover dentro de seu aplicativo de página única ou insere um URL na barra de endereço, as rotas mapeiam o 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 levará o usuário ao Azure AD B2C para autenticar.
Na pasta src/app , edite app-routing.module.ts 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ê adiciona os botões de entrada e saída ao componente do aplicativo . Na pasta src/app , abra o arquivo app.component.ts e faça as seguintes alterações:
Importe os componentes necessários.
Altere a classe para implementar o método OnInit. O
OnInitmétodo subscreve o evento observável MSAL MsalBroadcastServiceinProgress$. Use esse evento para saber o status das interações do usuário, especialmente para verificar se as interações foram concluídas.Antes de interações com o objeto de conta MSAL, verifique se a
InteractionStatuspropriedade retornaInteractionStatus.None. Osubscribeevento chama osetLoginDisplaymétodo para verificar se o usuário está autenticado.Adicione variáveis de classe.
Adicione o método
loginque inicia o fluxo de autorização.Adicione o
logoutmétodo que desconecta o usuário.Adicione o
setLoginDisplaymétodo que verifica se o usuário está autenticado.Adicione o método ngOnDestroy para limpar o
inProgress$evento subscribe.
Após as alterações, seu código deve se parecer com o 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 -app.component.html e faça as seguintes alterações:
- Adicione um link para o perfil e os componentes da API da Web.
- Adicione o botão de login com o atributo de evento de clique definido para o método
login(). Este botão aparece apenas se aloginDisplayvariável de classe forfalse. - Adicione o botão de desconexão e defina o seu atributo de evento de clique para o método
logout(). Este botão aparece apenas se aloginDisplayvariável de classe fortrue. - Adicione um elemento de saída do roteador .
Após as alterações, seu código deve se parecer com o 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 arquivo de app.component.css com o seguinte trecho CSS:
.toolbar-spacer {
flex: 1 1 auto;
}
a.title {
color: white;
}
Manipular os redirecionamentos do aplicativo
Ao usar redirecionamentos com o MSAL, você deve adicionar a diretiva de redirecionamento de aplicativo ao index.html. Na pasta src, edite index.html conforme mostrado no seguinte trecho de código:
<!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 arquivo styles.css com o seguinte trecho 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%; }
Sugestão
Neste ponto, você pode executar seu aplicativo e testar a experiência de entrada. Para executar seu aplicativo, consulte a seção Executar o aplicativo Angular .
Verificar se um usuário está autenticado
O arquivo home.component demonstra como verificar se o usuário está autenticado. Na pasta src/app/home , atualize home.component.ts com o seguinte trecho de código.
O código:
- Subscreve aos eventos observáveis de MSAL MsalBroadcastService
msalSubject$einProgress$. - Garante que o evento
msalSubject$escreva o resultado da autenticação na consola do navegador. - Garante que o
inProgress$evento verifique se um usuário está autenticado. OgetAllAccounts()método 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 , atualizehome.component.html com o seguinte trecho HTML. A diretiva *ngIf verifica a loginDisplay variável de classe 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>
Leia 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/profile , atualize profile.component.ts com o seguinte trecho de código.
O código:
- Importa os componentes necessários.
- Subscreve a um evento observável através do MSAL MsalBroadcastService
inProgress$. O evento carrega a conta e lê as declarações do token de identificação. - Garante que o
checkAndSetActiveAccountmétodo verifica e define a conta ativa. Essa ação é comum quando o aplicativo interage com vários fluxos de usuário do Azure AD B2C ou políticas personalizadas. - Garante que o
getClaimsmétodo obtenha as declarações de token de ID do objeto de conta MSAL ativo. Em seguida, o método adiciona as declarações àdataSourcematriz. A matriz é renderizada para o usuário com a vinculaçã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 , atualizeprofile.component.html com o seguinte trecho HTML:
<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 Angular HttpClient para recursos protegidos conhecidos.
Importante
O método de inicialização MSAL (na app.module.ts classe) mapeia recursos protegidos, como APIs da Web, com os âmbitos de aplicação necessários, usando o protectedResourceMap objeto. Se o código precisar chamar outra API da Web, adicione o URI da API da Web e o método HTTP da API da Web, com os escopos correspondentes, ao protectedResourceMap objeto. Para obter mais informações, consulte Mapa de recursos protegidos.
Quando o objeto HttpClient chama uma API da Web, o provedor MsalInterceptor executa as seguintes etapas:
Adquire um token de acesso com as permissões (escopos) necessárias para o ponto de extremidade da API Web.
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 uma API da Web. Na pasta src/app/webapi , atualize webapi.component.ts com o seguinte trecho de código.
O código:
- Usa a classe Angular HttpClient para chamar a API da Web.
- Lê o
auth-configelemento daprotectedResources.todoListApi.endpointclasse. Este elemento especifica o URI da API Web. Com base no URI da API da Web, o intercetador MSAL adquire um token de acesso com os escopos correspondentes. - Obtém o perfil da API da Web e define a
profilevariável de classe.
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 , atualizewebapi.component.html com o seguinte trecho HTML. O modelo do componente renderiza o nome que a API da Web retorna. Na parte inferior da página, o modelo renderiza o endereço da API da 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 CSS:
.footer-text {
position: absolute;
bottom: 50px;
color: gray;
}
Execute o aplicativo Angular
Execute o seguinte comando:
npm start
A janela do console exibe o número da porta onde o aplicativo está hospedado.
Listening on port 4200...
Sugestão
Como alternativa, para executar o npm start comando, use o depurador de código do Visual Studio. O depurador ajuda a acelerar o loop de edição, compilação e depuração.
Aceda a http://localhost:4200 no seu browser para ver a aplicação.