O foco deste tutorial é ajudar pessoas desenvolvedoras a aprender como proteger uma aplicação Angular implementando a autenticação de usuário. Você vai melhorar uma aplicação Angular inicial para praticar os seguintes conceitos de segurança:
- Adicionar login e logout de usuário.
- Recuperar informações de usuário.
- Proteger as rotas da aplicação.
- Chamar endpoints protegidos de uma API.
Este tutorial usa o SDK da Auth0 para proteger as aplicações Angular. O SDK abstrai muitos detalhes de implementação de autenticação para ajudar você a seguir as melhores práticas de segurança usando uma abordagem Angular idiomática enquanto escreve menos código. Você não precisa ser especialista em OAuth 2.0 ou OpenID Connect para entender como proteger sua coleção de aplicações web.
⏰⚡️ Se você tiver pouco tempo, confira O Guia de Início Rápido de Auth0 Angular.
Obtenha a Aplicação Inicial
Procure o emoji 🛠️ se quiser passar pelo conteúdo enquanto se concentra nas etapas de criação.
Criamos um projeto inicial usando a Interface de Linha de Comando (Command Line Interface - CLI) do Angular para te ajudar a aprender os conceitos de segurança do Angular através da prática. O projeto inicial usa Bootstrap com um tema personalizado para cuidar do estilo e do layout das suas aplicações para que você possa se concentrar na construção e ligação de componentes Angular.
🛠 Dessa forma, clone o repositório
auth0-angular-sample
em seu branch starter
para começar:git clone -b starter git@github.com:auth0-blog/auth0-angular-sample.git
🛠 Depois de clonar o repositório, torne
auth0-angular-sample
seu diretório atual:cd auth0-angular-sample
🛠 Instale as dependências do projeto Angular:
npm install
🛠 Por último, inicie a aplicação Angular:
npm start
Conecte O Angular Com a Auth0
Por que usar Auth0 em vez de criar sua própria autenticação de usuário do zero?
No passado, pessoas sábias alertavam: "não inventarás a tua própria criptomoeda". Hoje, pessoas sábias aconselham que "você não precisa construir sua própria autenticação".
Construir um sistema detalhado de autenticação e autorização do zero é complexo. A Auth0 é uma plataforma Identity-as-a-Service (IDaaS) que permite centralizar a autenticação de usuário e a autorização da API para todas as suas aplicações, a fim de reduzir essa complexidade.
A Auth0 oferece recursos de segurança poderosos prontos para usar. Uma página de login personalizável, login social, autenticação multifator (MFA) e gerenciamento avançado de usuários permitem que você coloque a sua aplicação no ar em tempo recorde. Talvez o recurso mais importante seja a detecção de anomalias, que ajuda a combater ataques de credential stuffing .
Na Auth0, os ataques de preenchimento de credenciais representam, em média, quase metade de todas as tentativas de login usando nossa plataforma. Leia mais detalhes sobre esse vetor de ataque crítico: Ataques de preenchimento de credenciais: o que são e como combatê-los (em inglês).
Como a Auth0 funciona?
- Você começa integrando a Auth0 com sua aplicação Angular.
- Quando seus usuários precisam fazer login, sua aplicação Angular aciona um evento de autenticação, que funciona redirecionando eles para uma página de login Auth0 personalizável.
- Depois que seus usuários fizerem login com sucesso, a Auth0 os redireciona de volta à sua aplicação Angular, retornando tokens com a autenticação e informações do usuário.
- Além disso, você pode proteger suas APIs com Auth0 para poder usar um token de acesso para fazer uma requisição da sua aplicação Angular para seus endpoints de API protegidos.
O quão fácil é começar?
Muito fácil! Só seguir esses passos:
Configure uma Aplicação Auth0
Se ainda não o fez, cadastre-se para obter uma conta Auth0 gratuita →
Se ainda não o fez,
cadastre-se para obter uma conta Auth0 gratuita →Uma conta gratuita oferece:
- 7.000 usuários ativos gratuitos e logins ilimitados.
- Uma página de login centralizada e pronta pra uso para Web, iOS e Android.
- Até 2 provedores de identidade social, como Google, GitHub e Twitter.
- Serverless ilimitados para personalizar e estender os recursos da Auth0.
Durante o cadastro, você cria um Auth0 Tenant, que é um container que a Auth0 usa para armazenar sua configuração de serviço de identidade e seus usuários isoladamente. Nenhum outro cliente Auth0 pode espiar ou acessar seu tenant.
🛠 Depois de se inscrever, Auth0 leva você para o Dashboard, onde você pode gerenciar e configurar seus serviços de identidade. No menu da barra lateral esquerda, clique em "Applications".
🛠 Em seguida, clique no botão "Create Application". Irá abrir um formulário para que você escreva o nome e escolha o tipo da aplicação.
- Name: (Nome)
Auth0 Angular Sample
- Application Type: (Tipo da aplicação)
Single Page Web Applications
🛠 Clique no botão "Create" para concluir o processo. A página da sua aplicação Auth0 é carregada.
Na próxima etapa, você aprenderá como ajudar o Angular e a Auth0 a se comunicarem usando os dados de configuração dessa página — não a feche ainda.
Qual é a relação entre Auth0 Tenants e aplicações Auth0?
Digamos que você tenha uma aplicação Angular de compartilhamento de fotos chamado “Angulogram”. Você então criaria um Auth0 tenant chamado
angulogram
.Agora, digamos que o Angulogram esteja disponível em três plataformas: na web como uma aplicação de página única (Single Page Application ou SPA em inglês) e como um aplicativo móvel nativo para Android e iOS. Se cada plataforma precisar de autenticação, você precisará criar três aplicações Auth0 para fornecer ao produto tudo o que a pessoa precisa para autenticar os usuários por meio dessa plataforma.
Crie uma ponte de comunicação entre Angular e Auth0
Ao usar a Auth0, você não precisa criar formulários de login. A Auth0 oferece uma página de login universal para reduzir a sobrecarga de adição e gerenciamento de autenticação.
É importante destacar que o formulário fornecido pela Auth0 (Auth0 Universal Login) reduz o risco de enumeração de nome de usuário e senha. O Login Universal da Auth0 implementa corretamente as mensagens de erro de autenticação seguindo as recomendações da OWASP (The Open Web Application Security Project): diga o suficiente para ajudar o usuário que está tentando entrar, mas não diga demais para evitar ajudar quem tenta invadir.
Como funciona oLogin Universal?
Sua aplicação Angular redirecionará os usuários para a Auth0 sempre que eles dispararem uma requisição de autenticação. A Auth0 irá apresentar uma página de login. Assim que eles fizerem login, a Auth0 os redirecionará de volta para a sua aplicação. Para que o redirecionamento ocorra com segurança, você deve especificar nas suas configurações de aplicações Auth0 as URLs para os quais a Auth0 pode redirecionar usuários, uma vez que estejam autenticados.
🛠 Clique na guia "Settings" da página da aplicação Auth0 e preencha os seguintes valores:
🛠 URLs de callback permitidas (Allowed Callback URLs em inglês)
http://localhost:4040
Depois que seus usuários fizerem login, a Auth0 só pode redirecioná-los para alguma das URLs que você listar aqui.
🛠URLs de logout permitidas (Allowed Logout URLs em inglês)
http://localhost:4040
Depois que seus usuários fizerem logout, a Auth0 só pode redirecioná-los para alguma das URLs que você listar aqui.
🛠 Origens Web permitidas (Allowed Web Origins em inglês)
http://localhost:4040
Usando o SDK da Auth0 para Angular, sua aplicação Angular fará requisições internas a uma URL da Auth0 para lidar com as requisições de autenticação. Você precisa adicionar a URL de origem da aplicação Angular para evitar problemas de Compartilhamento de recursos de origem cruzada (Cross-Origin Resource Sharing - CORS).
🛠 Role para baixo e clique no botão "Save changes".
🛠 Não feche esta página ainda. Você precisará de algumas informações na próxima seção.
Adicione as variáveis de configuração da Auth0 ao Angular
Na aba "Settings" da página da aplicação Auth0, você precisa dos valores de Domínio Auth0 (Auth0 Domain em inglês) e ID do Cliente (Client ID em inglês) para permitir que sua aplicação Angular use a ponte de comunicação que você criou.
O que exatamente é um domínio Auth0 e um ID de cliente Auth0?
Domínio Quando você criou uma nova conta Auth0, a Auth0 pediu para escolher um nome para seu tenant. Este nome, anexado com
auth0.com
, é o seu domínio Auth0 (Auth0 Domain em inglês). Depois de anexar o protocolo https://
, você obtém a URL base que sua aplicação Angular pode usar para redirecionar os usuários para fazer login e acessar as APIs Auth0:https://<TENANT-NAME>.auth0.com
Auth0 também oferece suporte a domínios personalizados para você preservar sua marca durante o processo de autenticação.
ID de Cliente
A Auth0 atribui um ID de cliente (Client ID) a cada aplicação que você cria no Dashboard da Auth0. O ID de cliente é uma string alfanumérica, e é o identificador exclusivo da sua aplicação no seu Auth0 tentant (como
q8fij2iug0CmgPLfTfG1tZGdTQyGaTUA
). Você não pode modificar o ID do cliente. Você usará o ID do cliente para identificar a aplicação Auth0 que o SDK da Auth0 para Angular precisa se conectar.Atenção: Outra informação crítica presente nas "Settings" é o Segredo do Cliente (Client Secret em inglês). Esse segredo protege seus recursos concedendo tokens apenas para solicitantes se tiverem autorização. Pense nisso como a senha da sua aplicação, que deve ser mantida em sigilo o tempo todo. Se alguém obtiver acesso ao seu segredo, poderá se passar pela sua aplicação e acessar recursos protegidos.
🛠 Abra o projeto inicial do Angular,
auth0-angular-sample
e crie um arquivoauth_config.json
no diretório do projeto:- macOS/Linux:
touch auth_config.json
- Windows Powershell:
ni auth_config.json
🛠 Preencha o
auth_config.json
da seguinte forma:{ "domain": "YOUR_AUTH0_DOMAIN", "clientId": "YOUR_AUTH0_CLIENT_ID" }
🛠 Volte para a página da aplicação Auth0. Siga estas etapas para obter os valores de
domain
e clientId
:- 🛠 Clique na guia "Settings", se ainda não tiver feito isso.
- 🛠 Use o valor "Domain" em "Settings" como o valor de
indomain
.auth_config.json
- 🛠 Use o valor "Client ID" em "Settings" como o valor de
noclientId
.auth_config.json
Essas variáveis permitem que sua aplicação Angular se identifique como uma parte autorizada para interagir com o servidor de autenticação Auth0 para continuar o processo. Você está mapeando a sua aplicação Angular para uma aplicação Auth0.
Para usar essas variáveis na sua aplicação Angular, você aproveitará o módulo
environment
Angular.🛠 Substitua o conteúdo de
src/environments/environment.ts
com o seguinte:// src/environments/environment.ts import { domain, clientId } from '../../auth_config.json'; export const environment = { production: false, auth: { domain, clientId, redirectUri: window.location.origin, }, };
Como é possível importar arquivos JSON dentro de um módulo Angular? O projeto inicial tem um arquivo
tsconfig.base.json
que modifica o resolveJsonModule
para true
, o que permite que você importe e extraia arquivos .json
.Conexão Auth0 e Angular
Você concluiu a configuração de um serviço de autenticação que sua aplicação Angular pode consumir. Continue construindo o projeto inicial ao longo deste guia, adicionando componentes de segurança.
Fique à vontade para se aprofundar na documentação da Auth0 para saber mais sobre como a Auth0 ajuda a economizar tempo na implementação e gerenciamento de identidade.
Configure O SDK Da Auth0 Para Angular
🛠 Você precisa seguir estas etapas para integrar o SDK da Auth0 com sua aplicação Angular.
Instale o SDK da Auth0 para Angular
🛠 Execute o seguinte comando:
ng add @auth0/auth0-angular
O SDK da Auth0 para Angular expõe vários métodos, variáveis e tipos que ajudam você a integrar a Auth0 com sua aplicação Angular idiomaticamente, incluindo um módulo e serviço de autenticação.
Registre e configure o módulo de autenticação
O SDK exporta um módulo com os componentes e serviços necessários para realizar a autenticação do usuário. Importe este módulo para o
AppModule
para acessá-lo por meio do framework de injeção de dependência do Angular.🛠 Importe
AuthModule
e environment
acima da definição @NgModule
em src/app/app.module.ts
dessa forma:// src/app/app.module.ts // Other imports... import { AuthModule } from '@auth0/auth0-angular'; import { environment as env } from '../environments/environment'; @NgModule({...}) export class AppModule {}
🛠 Então, adicione
AuthModule
ao AppModule
que foi importado e o inicialize:// src/app/app.module.ts // All imports... @NgModule({ declarations: [...], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, FontAwesomeModule, // 👇 add and initialize AuthModule AuthModule.forRoot({ ...env.auth, }), ], bootstrap: [...], }) export class AppModule {}
Você usa o padrão
para configurar forRoot()
AuthModule
, que obtém um objeto com as propriedades domain
e clientId
. Você cria esse objeto de configuração usando o objeto env.auth
.No entanto, a autenticação de usuário é um mecanismo para monitorar quem está acessando sua aplicação e controlar o que essas pessoas podem fazer. Por exemplo, você pode impedir que usuários que não tenham efetuado login acessem partes da sua aplicação. Nesse cenário, a Auth0 pode atuar como bouncer da aplicação.
Um bouncer é uma pessoa empregada por uma boate ou estabelecimento similar para impedir que encrenqueiros entrem ou os expulsem do local. A segurança do Angular não é muito diferente da segurança de uma boate.
Se os usuários quiserem acessar uma rota protegida da sua aplicação, a Auth0 irá interrompê-los e solicitar que apresentem suas credenciais. Se a Auth0 puder verificar quem são e se devem entrar lá, a Auth0 os deixará entrar. Caso contrário, a Auth0 os levará de volta para uma rota pública da aplicação.
Agora, é importante reiterar que o processo de autenticação não acontecerá na sua aplicação. Sua aplicação Angular redirecionará seus usuários para a página de login universal da Auth0, onde a Auth0 solicita as credenciais e redireciona o usuário de volta à sua aplicação com o resultado do processo de autenticação.
O SDK da Auth0 para Angular está configurado. Tudo pronto para criar componentes para implementar o fluxo de autenticação na próxima seção.
Adicione Autenticação De Usuários
O SDK da Auth0 para Angular fornece métodos para acionar eventos de autenticação: login, logout e inscrição.
Crie um botão de login
🛠 Crie um
LoginButtonComponent
dentro do diretório src/components/
usando a Angular CLI:ng generate component components/login-button --inlineStyle --skipTests
🛠 Preencha o arquivo
login-button.component.ts
no diretório src/app/components/login-button/
assim:// src/app/components/login-button/login-button.component.ts import { Component, OnInit } from '@angular/core'; import { AuthService } from '@auth0/auth0-angular'; @Component({ selector: 'app-login-button', templateUrl: './login-button.component.html', styles: [], }) export class LoginButtonComponent implements OnInit { constructor(public auth: AuthService) {} ngOnInit(): void {} loginWithRedirect(): void { this.auth.loginWithRedirect(); } }
🛠 Depois, preencha o template
login-button.component.html
no diretório src/app/components/login-button/
dessa forma:<!-- src/app/components/login-button/login-button.component.html --> <button class="btn btn-primary btn-block" (click)="loginWithRedirect()"> Log in </button>
Dentro da definição de
LoginButtonComponent
, auth.loginWithRedirect()
é um método exposto pelo AuthService
. Chamar esse método solicita que um usuário autentique e dê consentimento para que sua aplicação Angular acesse determinados dados em nome deste usuário. Em sua arquitetura atual, isso significa que sua aplicação Angular redireciona o usuário para a página de login universal da Auth0 para realizar o processo de autenticação. Você verá isso em ação nas próximas seções.Você pode passar um objeto de configuração para
loginWithRedirect()
para personalizar a experiência de login. Por exemplo, você pode passar opções para loginWithRedirect()
redirecionar usuários a uma página de login universal Auth0 otimizada para se inscrever na sua aplicação Angular. Consulte RedirectLoginOptions
(em inglês) para obter mais detalhes sobre essas opções.Crie um botão de inscrição
Você pode fazer com que os usuários acessem diretamente uma página de inscrição em vez de uma página de login, especificando a propriedade
screen_hint
no objeto de configuração auth.loginWithRedirect()
:{ screen_hint: "signup", }
🛠 Crie um
SignupButtonComponent
no diretório src/components/
usando Angular CLI:ng generate component components/signup-button --inlineStyle --skipTests
🛠 Preencha o arquivo
signup-button.component.ts
em src/app/components/signup-button/
assim:// src/app/components/signup-button/signup-button.component.ts import { Component, OnInit } from '@angular/core'; import { AuthService } from '@auth0/auth0-angular'; @Component({ selector: 'app-signup-button', templateUrl: './signup-button.component.html', }) export class SignupButtonComponent implements OnInit { constructor(public auth: AuthService) {} ngOnInit(): void {} loginWithRedirect(): void { this.auth.loginWithRedirect({ screen_hint: 'signup' }); } }
🛠 Preencha o arquivo base
signup-button.component.html
em src/app/components/signup-button/
dessa forma:<button class="btn btn-primary btn-block" (click)="loginWithRedirect()"> Sign Up </button>
O uso do recurso de inscrição exige que você ative o Auth0 New Universal Login Experience em seu tenant.
🛠 Abra a seção Login Universal do dashboard Auth0 e escolha a opção "New" na subseção "Experience".
🛠 Role para baixo e clique no botão "Save changes".
A diferença entre a experiência de usuário em
LoginButtonComponent
e SignupButtonComponent
ficará mais evidente quando você integrar esses componentes à aplicação Angular e vê-los em ação. Você fará isso nas próximas seçõesCrie um botão de logout
🛠 Crie um
LogoutButtonComponent
no diretório src/components/
:ng generate component components/logout-button --inlineStyle --skipTests
🛠 Preencha o arquivo
logout-button.component.ts
em src/app/components/logout-button/
com o código:// src/app/components/logout-button/logout-button.component.ts import { Component, Inject, OnInit } from '@angular/core'; import { AuthService } from '@auth0/auth0-angular'; import { DOCUMENT } from '@angular/common'; @Component({ selector: 'app-logout-button', templateUrl: './logout-button.component.html', styles: [], }) export class LogoutButtonComponent implements OnInit { constructor( public auth: AuthService, @Inject(DOCUMENT) private doc: Document, ) {} ngOnInit(): void {} logout(): void { this.auth.logout({ returnTo: this.doc.location.origin }); } }
Você está definindo um método
logout()
que aciona o evento fazer logout. Você passa pra ele um objeto de configuração opcional para informar à Auth0 para onde levar os usuários depois de fazer o logout.🛠 Depois, preencha o arquivo base
logout-button.component.html
em src/app/components/logout-button/
dessa forma:<!--src/app/components/logout-button/logout-button.component.html--> <button class="btn btn-danger btn-block" (click)="logout()">Log out</button>
O método
auth.logout()
exposto por AuthService
limpa a sessão da aplicação e redireciona para o endpoint Auth0 /v2/logout
para limpar a sessão Auth0. Com os métodos de login, você pode passar um argumento de objeto para logout()
para definir parâmetros para a chamada /v2/logout
. Este processo é praticamente invisível para o usuário. Consulte LogoutOptions
(em inglês) para obter mais detalhes.Aqui, você adiciona a propriedade
returnTo
para especificar a URL onde Auth0 deve redirecionar seus usuários após o logout. No momento, você está trabalhando localmente e as "Allowed Logout URLs" da sua aplicação Auth0 apontam para http://localhost:4040
.No entanto, se você for fazer o deploy da sua aplicação Angular para produção, será necessário adicionar a URL de logout de produção à lista "Allowed Logout URLs" e garantir que a Auth0 redirecione seus usuários para essa URL de produção e não para o
localhost
. Definir returnTo
como this.doc.location.origin
fará exatamente isso.Os componentes Angular não têm acesso direto ao objeto
document
. No entanto, você pode fazer @Inject
na constante DOCUMENT
como uma dependência de AuthenticationButtonComponent
. this.doc
é igual ao documento DOM o no navegador. this.doc.location
retorna um objeto Location
cuja propriedade origin
é a origem da sua aplicação.Leia mais sobre como funciona o Logout na Auth0 (em inglês).
Integre os botões de login e logout
Vamos envolver o
LoginButtonComponent
e LogoutButtonComponent
em um único componente que tem lógica para decidir qual botão renderizar dependendo do status de autenticação do usuário.🛠 Crie
AuthenticationButtonComponent
no diretório src/app/components/
:ng g c components/authentication-button --inlineStyle --skipTests
Você está usando a abreviação
(g
) egenerate
(c
) para tornar o comando mais curto.component
🛠 Preencha o arquivo
authentication-button.component.ts
no diretório src/app/components/authentication-button/
assim:// src/app/components/authentication-button/authentication-button.component.ts import { Component, OnInit } from '@angular/core'; import { AuthService } from '@auth0/auth0-angular'; @Component({ selector: 'app-authentication-button', templateUrl: './authentication-button.component.html', styles: [], }) export class AuthenticationButtonComponent implements OnInit { constructor(public auth: AuthService) {} ngOnInit(): void {} }
🛠 Preencha o arquivo
authentication-button.component.html
no diretório src/app/components/authentication-button/
dessa forma:<!-- src/app/components/authentication-button/ authentication-button.component.html --> <app-login-button *ngIf="(auth.isAuthenticated$ | async) === false"> </app-login-button> <app-logout-button *ngIf="auth.isAuthenticated$ | async"> </app-logout-button>
Vamos começar entendendo o que está acontecendo no arquivo base.
auth.isAuthenticated$
é um Observable
exposto por AuthService
que emite um valor booleano. Seu valor é true
quando a Auth0 autenticou o usuário e false
quando não o fez.É importante observar que, por baixo dos panos,
auth.isAuthenticated$
só começa a emitir valores quando o SDK da Auth0 para Angular termina de carregar. Quando AuthService.isLoading$
emite false
, então auth.isAuthenticated$
emite seu valor. Esse encadeamento de operações ajuda a evitar falsos positivos em relação ao status de autenticação de um usuário. Isso também causa um pequeno atraso na renderização do AuthenticationButtonComponent
, mas você corrigirá isso em breve.Existem algumas vantagens em usar o wrapper de componente
AuthenticationButtonComponent
:Você pode construir interfaces flexíveis.
AuthenticationButtonComponent
serve como uma opção de "login/logout" que você pode colocar em qualquer lugar que precisar dessa funcionalidade de troca. No entanto, você ainda tem componentes LoginButtonComponent
e LogoutButtonComponent
separados para os casos em que você precise de sua funcionalidade de forma isolada. Por exemplo, você pode ter um botão de logout em uma página que somente usuários autenticados podem ver.Você pode construir interfaces extensíveis. Você pode facilmente trocar o componente
LoginButtonComponent
por SignupButtonComponent
em AuthenticationButtonComponent
para criar uma opção de "sign up/log out". Você também pode envolver a opção "sign up/log out" em um componente NewAuthenticationButtonComponent
se quiser.Você pode construir interfaces declarativas. Usando
AuthenticationButtonComponent
, você pode adicionar a funcionalidade de login e logout ao seu componente NavBarComponent
, por exemplo, sem pensar nos detalhes de implementação de como a troca de autenticação funciona.🛠 Com isso em mente, crie um
AuthNavComponent
no diretóriosrc/components/
:ng g c components/auth-nav --inlineStyle --skipTests
🛠 Preencha o arquivo
auth-nav.component.html
no diretório src/app/components/auth-nav/
assim:<!--src/app/components/auth-nav/auth-nav.component.html--> <div class="navbar-nav ml-auto"> <app-authentication-button></app-authentication-button> </div>
🛠 Finalmente, abra o arquivo base
nav-bar.component.html
no diretório src/app/components/nav-bar/
e atualize-o assim:<!--src/app/components/nav-bar/nav-bar.component.html--> <div class="nav-container mb-3"> <nav class="navbar navbar-expand-md navbar-light bg-light"> <div class="container"> <div class="navbar-brand logo"></div> <app-main-nav></app-main-nav> <app-auth-nav></app-auth-nav> </div> </nav> </div>
Por ter diferentes tipos de subcomponentes da barra de navegação, você pode estender cada um conforme necessário, sem reabrir e modificar o componente
MainNavComponent
.🛠 Vá em frente e tente fazer o login. Sua aplicação Angular redireciona você para a página de login universal da Auth0. Você pode usar um formulário para fazer login com um nome de usuário e senha ou um provedor de identidade social como o Google. Observe que esta página de login também oferece a opção de se inscrever.
Experimento: Use SignupButtonComponent
SignupButtonComponent
Troque o componente
LoginButtonComponent
pelo componente SignupButtonComponent
no arquivo base AuthenticationButtonComponent
.Ao clicar no botão "Sign Up" (Inscreva-se), você será direcionado para uma página com linguagem otimizada para incentivar a se inscrever em sua aplicação Angular.
Experimente isso!
Depois de concluir esse teste, troque
SignupButtonComponent
por LoginButtonComponent
para continuar com o restante deste guia.Você pode personalizar a aparência das novas páginas de Login Universal. Você também pode substituir qualquer texto na "New Experience" usando a API de Personalização de Texto.**
Observe que, quando você termina de fazer login e a Auth0 redireciona você para sua aplicação Angular, a interface do usuário apresenta uma tela piscando.
A interface do usuário "pisca" porque sua aplicação Angular está carregando os serviços. Enquando ela carrega, o Angular não sabe se a Auth0 já autenticou o usuário. Sua aplicação saberá o status de autenticação do usuário depois que o SDK da Auth0 para Angular for carregado.
🛠 Para corrigir a intermitência da interface de usuário (UI), use o Observable
auth.isLoading$
exposto pelo AuthService
que emite um valor booleano para renderizar o componente AppComponent
assim que o SDK da Auth0 para Angular terminar de carregar.🛠 Abra o arquivo
src/app/app.component.ts
e atualize-o da seguinte forma:// src/app/app.component.ts import { Component } from '@angular/core'; import { AuthService } from '@auth0/auth0-angular'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent { constructor(public auth: AuthService) {} }
🛠 Abra o arquivo
src/app/app.component.html
e atualize-o da seguinte forma:<!--src/app/app.component.html--> <div id="app" class="d-flex flex-column h-100"> <div class="container" *ngIf="auth.isLoading$ | async; else loaded"> <app-loading></app-loading> </div> <ng-template #loaded> <app-nav-bar></app-nav-bar> <div class="container flex-grow-1"> <div class="mt-5"> <router-outlet></router-outlet> </div> </div> <app-footer></app-footer> </ng-template> </div>
Enquanto o SDK está carregando, o componente de carregamento
LoadingComponent
, que é animado, é renderizado.Recupere Informações De Usuário
Depois que um usuário efetua login com sucesso, Auth0 envia um ID token para sua aplicação Angular. Os sistemas de autenticação, como Auth0, usam ID tokens na autenticação baseada em token para armazenar em cache as informações do perfil do usuário e fornecê-las a uma aplicação cliente. O armazenamento em cache de ID tokens pode contribuir para melhorias no desempenho e capacidade de resposta da sua aplicação Angular.
Você pode usar os dados do ID token para personalizar a interface do usuário da sua aplicação Angular. O SDK da Auth0 para Angular decodifica o ID token e apresenta seus dados através do Observable
auth.user$
exposto pelo AuthService
. Algumas das informações do ID token incluem o nome, apelido, imagem e e-mail do usuário conectado.Como você pode usar o ID token para criar uma página de perfil para seus usuários?
🛠 Atualize o componente
ProfileComponent
em src/app/pages/profile/profile.component.ts
da seguinte forma:// src/app/pages/profile/profile.component.ts import { Component, OnInit } from '@angular/core'; import { AuthService } from '@auth0/auth0-angular'; @Component({ selector: 'app-profile', templateUrl: './profile.component.html', }) export class ProfileComponent implements OnInit { profileJson: string = null; constructor(public auth: AuthService) {} ngOnInit(): void { this.auth.user$.subscribe( (profile) => (this.profileJson = JSON.stringify(profile, null, 2)), ); } }
🛠 Atualize o componente base
ProfileComponent
em src/app/pages/profile/profile.component.html
da seguinte forma:<!--src/app/pages/profile/profile.component.html--> <div *ngIf="auth.user$ | async as user"> <div class="row align-items-center profile-header"> <div class="col-md-2 mb-3"> <img [src]="user.picture" alt="User's profile picture" class="rounded-circle img-fluid profile-picture" /> </div> <div class="col-md text-center text-md-left"> <h2>{{ user.name }}</h2> <p class="lead text-muted">{{ user.email }}</p> </div> </div> <div class="row" *ngIf="profileJson"> <pre class="col-12 text-light bg-dark p-4">{{ profileJson }}</pre> </div> </div>
O que está acontecendo no componente
ProfileComponent
?ngOnInit()
é o melhor lugar para inicializar dados para um componente Angular. Assim, você assina o Observable this.auth.user$
no ProfileComponent
. Depois que this.auth.user$
emite o objeto de perfil de usuário, você usa JSON.stringify
para formatar o objeto e atribuí-lo a this.profileJson
. Por sua vez, você usa a diretiva *ngIf
para renderizar uma caixa de código com o objeto JSON de perfil de usuário com base no valor de profileJson
.O componente
ProfileComponent
renderiza informações do usuário que você pode considerar protegidas. Além disso, a propriedade do user
é null
se não houver um usuário conectado. Portanto, de qualquer forma, este componente só deve renderizar se a Auth0 tiver autenticado o usuário.Como tal, você deve proteger a rota que renderiza este componente,
. Você aprenderá a fazer exatamente isso na próxima seção.http://localhost:4040/profile
Proteja Rotas
De todas as seções deste guia, esta é a mais fácil de implementar graças à robustez do Angular Router. O SDK da Auth0 para Angular expõe um
que você pode usar para proteger rotas.AuthGuard
🛠 Abra
src/app/app-routing.module.ts
e atualize-o da seguinte maneira:// src/app/app-routing.module.ts import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { HomeComponent } from 'src/app/pages/home/home.component'; import { ProfileComponent } from 'src/app/pages/profile/profile.component'; import { ExternalApiComponent } from 'src/app/pages/external-api/external-api.component'; import { AuthGuard } from '@auth0/auth0-angular'; const routes: Routes = [ { path: '', component: HomeComponent, pathMatch: 'full', }, { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard], }, { path: 'external-api', component: ExternalApiComponent, canActivate: [AuthGuard], }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], }) export class AppRoutingModule {}
Exigir login de usuário para acessar uma rota é fácil: basta incluir a propriedade
canActivate
na definição da rota e adicionar AuthGuard
como seu valor. Quando os usuários que não efetuaram login acessarem essa rota, sua aplicação Angular os redirecionará para a página de login. Depois que o usuário fizer login, Auth0 redirecionará o usuário para sua aplicação Angular e o AuthService
levará os usuários à página que eles desejavam acessar antes do login.🛠 Agora você pode testar se esses dois caminhos,
/profile
e /external-api
, exigem que os usuários façam login antes de acessá-los. Faça o log out e tente acessar a página Profile ou External API. Se funcionar, o Angular redireciona você para fazer o login com Auth0.
Os protetores do lado do cliente melhoram a experiência do usuário em sua aplicação Angular, não sua segurança.
No Security StackExchange, Conor Mancone explica que as proteções do lado do servidor visam proteger os dados, enquanto as proteções do lado do cliente visam melhorar a experiência do usuário.
As principais conclusões de sua resposta são:
- Você não pode confiar em restrições do lado do cliente, como protetores de navegação e rotas protegidas, para proteger informações confidenciais.
- Os invasores podem eventualmente contornar as restrições do lado do cliente.
- Seu servidor não deve retornar nenhum dado que um usuário não deva acessar.
- Retornar todos os dados do usuário do servidor e permitir que o framework de front-end decida o que exibir e o que ocultar com base no status de autenticação do usuário é uma abordagem errada.
- Qualquer pessoa pode abrir as ferramentas de desenvolvimento do navegador e inspecionar as requisições de rede para visualizar todos os dados.
- O uso de protetores de navegação ajuda a melhorar a experiência do usuário, não a segurança do usuário. - Sem protetores, um usuário que não fez login pode entrar em uma página com informações restritas e ver um erro, como "Acesso negado". - Com protetores que correspondem às permissões do servidor, você pode impedir que os usuários vejam erros, impedindo-os de visitar a página restrita.
Chame Uma API
Esta seção se concentra em mostrar como obter um token de acesso (access token, em inglês) na sua aplicação Angular e como usá-lo para fazer chamadas de API para endpoints protegidos.
Ao usar a Auth0, você delega o processo de autenticação a um serviço centralizado. A Auth0 oferece a funcionalidade de fazer login e logout de usuários da aplicação Angular. No entanto, sua aplicação pode precisar acessar recursos protegidos de uma API.
Você também pode proteger uma API com Auth0. Existem vários guias de início rápido de API para te ajudar a integrar a Auth0 com sua plataforma de back-end.
Ao usar a Auth0 para proteger sua API, você também delega o processo de autorização a um serviço centralizado que garante que apenas aplicações de cliente aprovadas possam acessar recursos protegidos em nome de um usuário.
Como você pode fazer chamadas de API seguras a partir do Angular?
Sua aplicação Angular autentica o usuário e recebe um token de acesso da Auth0. A aplicação pode então passar esse token de acesso para sua API como uma credencial. Por sua vez, sua API pode usar bibliotecas Auth0 para verificar o token de acesso que recebe da aplicação e emitir uma resposta com os dados desejados.
Em vez de criar uma API do zero para testar os fluxos de autenticação e autorização entre o cliente e o servidor, você usará uma API de demonstração Express API que preparei para você.
Obtenha a API de demonstração Express API
🛠 Abra o terminal em uma nova janela e clone o repositório
auth0-express-js-sample
em algum lugar do sistema. Certifique-se de fazer o clone fora do diretório do projeto Angular.git clone git@github.com:auth0-blog/auth0-express-js-sample.git
🛠 Depois de clonar este repositório, torne o diretório
seu diretório atual:auth0-express-js-sample
cd auth0-express-js-sample
🛠 Instale as dependências do projeto Node.js:
npm install
Conecte a Express API com Auth0
Crie uma ponte de comunicação entre Angular e Auth0
Este processo é semelhante a como você conectou o Angular à Auth0.
🛠 Vá para a seção APIs no Dashboard da Auth0 e clique no botão "Create API".
🛠 Então, no formulário que a Auth0 mostra:
- Adicione um nome à sua API:
Auth0 Express Sample
- Defina seu valor de identificador:
https://express.sample
- Deixe o algoritmo de assinatura como
, pois é a melhor opção do ponto de vista de segurança.RS256
Identificadores são strings únicas que ajudam a Auth0 a diferenciar suas APIs. Recomendamos o uso de URLs para facilitar a criação de identificadores únicos de maneira previsível; no entanto, a Auth0 nunca chama essas URLs.
🛠 Com esses valores preenchidos, clique no botão "Create". Mantenha esta página aberta, pois você precisará de alguns de seus valores na próxima seção.
Adicione as variáveis de configuração da Auth0 à Express
🛠 Crie um arquivo .
env
para o servidor da API no diretório auth0-express-js-sample:
touch .env
🛠 Preencha este arquivo
auth0-express-js-sample/.env
da seguinte forma:SERVER_PORT=6060 CLIENT_ORIGIN_URL=http://localhost:4040 AUTH0_AUDIENCE= AUTH0_DOMAIN=
🛠 Volte para a página da API no dashboard da Auth0 e siga estas etapas para obter a Auth0 Audience:
- 🛠 Clique na guia "Settings".
- 🛠 Localize o campo "Identifier" e copie seu valor.
- 🛠 Cole o valor "Identifier" como o valor de
no arquivoAUTH0_AUDIENCE
..env
Agora, siga estas etapas para obter o valor do Auth0 Domain:
- 🛠 Clique na aba "Test".
- 🛠 Localize a seção chamada "Asking Auth0 for tokens from my application".
- 🛠 Clique na guia cURL para mostrar uma requisição
de exemplo.POST
- 🛠 Copie seu domínio Auth0, que faz parte do valor do parâmetro
.--url: nome-do-tenant.regiao.auth0.com
- 🛠 Cole o valor do domínio Auth0 como o valor de
no arquivoAUTH0_DOMAIN
..env
Dicas para obter o Auth0 Domain
- O Auth0 Domain é a substring entre o protocolo,
e o caminhohttps://
./oauth/token
- O Auth0 Domain segue este padrão:
.nome-do-tenant.regiao.auth0.com
- O subdomínio da região (
,au
ouus
) é opcional. Alguns domínios Auth0 não o possuem.eu
- Clique na imagem acima, por favor, se tiver alguma dúvida de como obter o valor do Auth0 Domain.
🛠 Com os valores de configuração
.env
definidos, rode o servidor da API executando o seguinte comando:npm start
Configure o Angular para se conectar com a Express API
🛠 Volte para o diretório do projeto
auth0-angular-sample
que armazena sua aplicação Angular.🛠 Localize o arquivo
auth_config.json
e adicione seus valores audience e server URL a ele:{ "domain": "YOUR_AUTH0_DOMAIN", "clientId": "YOUR_AUTH0_CLIENT_ID", "audience": "https://express.sample", "serverUrl": "http://localhost:6060" }
🛠 O valor de
audience
é o mesmo que AUTH0_AUDIENCE
que você colocou no arquivo auth0-express-js-sample/.env
.🛠 Localize o arquivo
src/environments/environment.ts
e atualize-o dessa forma:// src/environments/environment.ts import { domain, clientId, audience, serverUrl } from '../../auth_config.json'; export const environment = { production: false, auth: { domain, clientId, redirectUri: window.location.origin, audience, }, dev: { serverUrl, }, };
Sua aplicação Angular precisa passar um token de acesso ao chamar uma API de destino para acessar recursos protegidos.
O SDK da Auth0 para Angular fornece um
HttpInjector
que anexa automaticamente tokens de acesso a requisições de saída ao usar o módulo integrado do Angular HttpClient
. No entanto, você deve configurar o injetor para saber a quais requisições ele precisa anexar os tokens de acesso.🛠 Comece importando o token
HTTP_INTERCEPTORS
e o AuthHttpInterceptor
exatamente acima da definição @NgModule
no arquivo src/app/app.module.ts
:// src/app/app.module.ts // Other imports... import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { AuthHttpInterceptor } from '@auth0/auth0-angular'; @NgModule({...}) export class AppModule {}
Você está importanto
AuthHttpInterceptor
de @auth0/auth0-angular
junto de HTTP_INTERCEPTORS
do @angular/common/http
. HTTP_INTERCEPTORS
é um multi-provedor de tokens que representa o vetor de objetos HttpInterceptor
registrados.🛠 Depois, adicione a propriedade
providers
ao objeto de configuração do AppModule
da seguinte forma para registrar o injetor AuthHttpInterceptor
como provedor:// src/app/app.module.ts // All imports... @NgModule({ declarations: [...], imports: [...], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true, }, ], bootstrap: [AppComponent], }) export class AppModule {}
Isso completa a ligação necessária para conectar o
AuthHttpInterceptor
ao seu ciclo de requisições da sua aplicação Angular.Agora, você precisa informar ao SDK a quais requisições anexar tokens de acesso configurando
AuthModule.forRoot()
. Com base nessa configuração, o Angular corresponderá à URL de qualquer requisição que você fizer usando HttpClient
em uma lista de URLs permitidas.Se houver uma correspondência, o Angular anexa um token de acesso ao cabeçalho de autorização da requisição. Você pode usar uma string ou uma expressão regular para a correspondência de URL. Por enquanto, você permitirá que o Angular anexe um token de acesso às requisições feitas para
http://localhost:6060/api/messages/protected-message
.🛠 Atualize a configuração do
AuthModule
presente no módulo imports
do AppModule
assim:// src/app/app.module.ts // All imports... @NgModule({ declarations: [...], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, FontAwesomeModule, // 👇 update AuthModule AuthModule.forRoot({ ...env.auth, httpInterceptor: { allowedList: [`${env.dev.serverUrl}/api/messages/protected-message`], }, }), ], providers: [...], bootstrap: [...], }) export class AppModule {}
Suponha que você faça uma chamada HTTP usando
HttpClient
e não haja correspondência para essa URL no AuthHttpInterceptor
. Nesse caso, o Angular ignora o interceptor e faz a chamada sem um token anexado no cabeçalho Authorization
.Observação: explicitar sobre quais requisições de API exigem um token de acesso no cabeçalho de autorização evita que seus tokens sejam anexados a requisições feitas a um destinatário não intencional, o que é um sério problema de segurança. Esses destinatários podem usar esse token para chamar a API como se fosse sua aplicação.
Por fim, faça sua chamada de API usando o
HttpClient
, que está disponível, pois o HttpClientModule
já foi importado no projeto inicial.🛠 Atualize
src/app/pages/external-api/external-api.component.ts
da seguinte forma:// src/app/pages/external-api/external-api.component.ts import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { environment as env } from '../../../environments/environment'; interface Message { message: string; } @Component({ selector: 'app-external-api', templateUrl: './external-api.component.html', }) export class ExternalApiComponent implements OnInit { message: string = null; constructor(private http: HttpClient) {} ngOnInit(): void {} callApi(): void { this.http .get(`${env.dev.serverUrl}/api/messages/public-message`) .subscribe((result: Message) => { this.message = result.message; }); } callSecureApi(): void { this.http .get(`${env.dev.serverUrl}/api/messages/protected-message`) .subscribe((result: Message) => { this.message = result.message; }); } }
⚠️ Verifique se a URL que você está chamando usando
corresponde à regra que você tem em sua configuração HttpClient
. Cuidado com as barras à direita.httpInterceptor
🛠 Atualize
src/app/pages/external-api/external-api.component.html
assim:<!--src/app/pages/external-api/external-api.component.html--> <div> <h1>External API</h1> <p> Use these buttons to call an external API. The protected API call has an access token in its authorization header. The API server will validate the access token using the Auth0 Audience value. </p> <div class="btn-group mt-5" role="group" aria-label="External API Requests Examples" > <button (click)="callApi()" type="button" class="btn btn-primary"> Get Public Message </button> <button (click)="callSecureApi()" type="button" class="btn btn-primary"> Get Protected Message </button> </div> <div *ngIf="message" class="mt-5"> <h6 class="muted">Result</h6> <div class="container-fluid"> <div class="row"> <code class="col-12 text-light bg-dark p-4"> {{ message }} </code> </div> </div> </div> </div>
O que está acontecendo agora no componente
ExternalApi
?Você adiciona um método
callApi()
que executa uma requisição de API pública e um método callSecureApi()
que executa uma requisição de API segura. A implementação de cada método parece a mesma. No entanto, por baixo dos panos, o Angular encontra uma correspondência para ${env.dev.apiUrl}/api/messages/protected-message
na allowedList
do AuthHttpInterceptor
.Em seguida, o Angular usa o SDK da Auth0 para obter um token de acesso de Auth0 e anexa esse token de acesso como uma credencial do tipo bearer no cabeçalho de autorização da requisição.
Em seguida, você atribui o resultado da requisição bem-sucedida a
this.message
, que é renderizada na interface do usuário usando uma caixa de código.Por que o valor de audiência da Auth0 é o mesmo para as duas aplicações?
Auth0 usa o valor da propriedade
audience
para determinar qual servidor de recursos (API) o usuário está autorizando sua aplicação Angular a acessar.As ações que sua aplicação Angular podem executar na API dependem dos escopos contidos no seu token de acesso, que você define como o valor de uma propriedade de escopo nas
de uma entrada de tokenOptions
httpInterceptor.allowedList
.Lembra daquela tela que você viu quando fez login pela primeira vez com Auth0 pedindo permissão para acessar as informações de seu perfil? Sua aplicação Angular fará a requisição da autorização do usuário para acessar os escopos requisitados e o usuário aprovará ou negará a requisição. Essa tela é conhecida como caixa de diálogo de consentimento. Você pode ter visto algo semelhante ao compartilhar seus contatos ou fotos de uma plataforma de mídia social com uma aplicação de terceiros.
Quando você não passa uma propriedade
scope
para tokenOptions
, o SDK da Auth0 para Angular usa por padrão os escopos do OpenID Connect: openid profile email
.
: Este escopo informa ao servidor de autorização Auth0 que o cliente está fazendo uma requisição OpenID Connect (OIDC) para verificar a identidade do usuário. OpenID Connect é um protocolo de autenticação.openid
: este valor de escopo requer acesso às informações de perfil padrão do usuário, comoprofile
,name
enickname
.picture
: este valor de escopo requer acesso às informações deemail
eemail
.email_verified
Os detalhes dos escopos do OpenID Connect vão para o ID token.
No caso das suas APIs, você pode definir escopos de API personalizados para implementar o controle de acesso. Você os identificará nas chamadas que suas aplicações clientes fazem para essa API. Auth0 inclui escopos de API no token de acesso como o valor de declaração de scope.
Os conceitos sobre escopos ou permissões de API são melhor abordados em um tutorial de API Auth0, como "Use TypeScript to Create a Secure API with Node.js and Express: Role-Based Access Control".
Sua requisição de login anterior não incluía um parâmetro de audiência. Como tal, o Angular SDK não tem um token de acesso armazenado na memória.
Você não deve armazenar tokens em localStorage
. Por quê?
localStorage
. Por quê? Armazenar tokens no armazenamento local do navegador fornece persistência nas atualizações de página e guias do navegador. No entanto, se um invasor puder rodar JavaScript na aplicação de página única (Single Page Application ou SPA em inglês) usando um ataque de script entre sites (XSS), ele poderá recuperar os tokens armazenados no local storage.
Uma vulnerabilidade que leva a um ataque XSS bem-sucedido pode estar no código-fonte da SPA ou em qualquer código JavaScript de terceiros incluído no SPA, como Bootstrap, jQuery ou Google Analytics.
🛠 Efetue logout e login novamente para obter um novo token de acesso do Auth0 que inclui as informações de audiência.
🛠 Visite
e clique em qualquer um dos botões na página da External API para testar as respostas.http://localhost:4040/external-api
Obtenha a mensagem pública:
The API doesn't require an access token to share this message.
Obtenha a mensagem protegida:
The API successfully validated your access token.
Conclusão
Você implementou a autenticação de usuário no Angular para identificar seus usuários, obter informações de perfil de usuário e controlar o conteúdo que seus usuários podem acessar. Você também aprendeu como fazer chamadas para API seguras entre um cliente e um servidor de uma pilha protegida com Auth0.
Este tutorial mostrou o caso de uso de autenticação mais comum para uma aplicação Angular: login e logout simples. No entanto, a Auth0 é uma plataforma extensível e flexível que pode te ajudar a chegar mais longe. Se você tiver um caso de uso mais complexo, verifique os Auth0 Architecture Scenarios para saber mais sobre os cenários de arquitetura típicos que identificamos ao trabalhar com clientes na implementação da Auth0.
Num próximo tutorial, vamos cobrir padrões e ferramentas de autenticação avançados, como usar um pop-up em vez de um redirecionamento para fazer login de usuários, adicionar permissões a ID tokens, usar metadados para aprimorar perfis de usuário e muito mais.
Deixe-me saber nos comentários abaixo se você gostou deste tutorial. Obrigado por ler este post e fica de olho para mais posts como esse.
About the author
Dan Arias
Staff Developer Advocate
The majority of my engineering work revolves around AWS, React, and Node, but my research and content development involves a wide range of topics such as Golang, performance, and cryptography. Additionally, I am one of the core maintainers of this blog. Running a blog at scale with over 600,000 unique visitors per month is quite challenging!
I was an Auth0 customer before I became an employee, and I've always loved how much easier it is to implement authentication with Auth0. Curious to try it out? Sign up for a free account ⚡️.View profile