No meu artigo anterior eu falei sobre Angular Lazy Loading. Hoje irei demonstrar como proteger as nossas rotas utilizando o Route Guards.
Esse artigo será dividido em duas partes; nessa primeira irei apresentar duas formas de gerenciamento: CanActivate e o CanActivateChild. Para quem não conhece o Guard, em um breve resumo ele nos permite gerenciar a navegação de nossas rotas. Abaixo criarei alguns exemplos para que você possa entender melhor.
Existem quatro tipos diferentes de Guard:
- CanActivate: válida se a rota está ativa
- CanActivateChild: válida se a rota filha está ativa
- CanDeactivate: verifica se uma rota pode ser desativada
- CanLoad: válida se um módulo está utilizando o lazily loading
Implementando Guards
Para demonstrar a implementação do Guards eu irei utilizar um projeto desenvolvido no meu artigo anterior (mencionado acima). Caso você tenha interesse em baixar ele, segue o link no GitHub:
O primeiro passo será criar uma interface. Para isso, abra um terminal no seu computador, navegue até o projeto clonado e em seguida execute o seguinte comando:
ng g s guards/AuthGuard
Esse comando criará uma nova pasta dentro de app, chamada guards, com dois arquivos: auth-guard.service.ts e auth-guard.service.spec.ts. Abra o arquivo auth-guard.service.ts e atualize ele com o seguinte trecho de código:
import { Injectable } from '@angular/core'; import { CanActivate } from '@angular/router'; @Injectable({ providedIn: 'root' }) export class AuthGuardService implements CanActivate { constructor() { } private isAuthenticated: boolean = false; canActivate() { return this.isAuthenticated; } }
Conforme você pode ver na imagem abaixo, o método canActivate retorna um boolean. Eu deixei seu retorno como false para protegermos o HomeModule.

O próximo passo será adicionar o AuthGuardService nos providers do AppModule. Para isso, abra o arquivo: ./app/app.module.ts e adicione o trecho de código abaixo:
providers: [AuthGuardService],
Testando o CanActivate
Agora execute o comando ng serve no seu terminal, e em seguida abra o endereço http://localhost:4200/ no seu navegador. Abaixo você tem uma imagem demonstrando o resultado desse passo:

Como essa rota está protegida, nós não conseguimos acessar o HomeModule.
Agora altere o retorno da variável isAuthenticated em AuthGuardService para true e de um refresh na tela. Note que agora a rota está acessível.

CanActivateChild
Existem cenários onde precisaremos criar um módulo com componentes e esses componentes com filhos. Em projetos desenvolvidos com Angular, nós podemos utilizar as rotas children.
Para ficar mais claro, vamos criar um novo módulo chamado produtos. Abra o seu terminal novamente e execute o comando abaixo:
ng g m products --routing
Esse comando criará um novo módulo chamado products. Vamos agora criar três novos componentes dentro dele:
ng g c products/product-list ng g c products/product-details ng g c products/product-details/overview
Agora abra o seu arquivo products-routing.module.ts e atualize ele com o trecho de código abaixo:
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { ProductListComponent } from './product-list/product-list.component'; import { ProductDetailsComponent } from './product-details/product-details.component'; import { OverviewComponent } from './product-details/overview/overview.component'; import { AuthGuardChildService } from '../guards/auth-guard-child.service'; const routes: Routes = [ { path: '', component: ProductListComponent }, { path: 'product-details/:id', canActivateChild: [AuthGuardChildService], children: [ { path: '', component: ProductDetailsComponent }, { path: 'overview', component: OverviewComponent } ] } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class ProductsRoutingModule { }
Em seguida adicione o ProductsModule em app-routing.module.ts.
{ path: 'products', loadChildren: './products/products.module#ProductsModule' },
O próximo passo será a criação de um serviço para implementarmos o CanActivateChild. Para isso, execute o comando abaixo no seu terminal:
ng g s guards/AuthGuardChild
Esse comando criará dois arquivos dentro do diretório app/guards/. Abra o auth-guard-child.service.ts e atualize ele com o trecho de código abaixo:
CanActivateChild
import { Injectable } from '@angular/core'; import { CanActivateChild, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthGuardChildService implements CanActivateChild { private isAuthenticated: boolean = true; canActivateChild( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean { return this.isAuthenticated; } }
Analisando o código acima, nós temos:
- 08: implementando a interface CanActivateChild
- 10: criação de uma variável para simularmos um usuário logado
- 13: estamos recebendo um snap da rota ativada
- 14: estamos recebendo o estado da rota ativa
Esse método deve retornar: Observable<boolean> | boolean
Testando o CanActivateChild
Agora execute o comando ng serve
e abra o endereço http://localhost:4200/ no seu navegador. Em seguida, tente acessar as rotas abaixo:
http://localhost:4200/products (irá apresentar o conteúdo de list) http://localhost:4200/products/product-details/13 (deve direcionar para home do projeto)
Abaixo você tem uma imagem demonstrando esse passo:

Agora, para liberar essa rota basta alterar o valor da variável isAuthenticated em auth-guard-child.service.ts para true. Abaixo você tem uma imagem demonstrando esse passo:

Para que verificarmos o retorno dos parâmetros route e state, atualize o arquivo guard-child.service.ts com o trecho de código abaixo:
canActivateChild( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean { console.log(route); console.log(state); return this.isAuthenticated; }
Em seguida, abra a rota no seu navegador: /products/product-details/13. Para analisar os dados de retorno eu irei utilizar a ferramenta tools do Chrome.
Abaixo você tem duas imagens demonstrando esses resultados.

Agora, expandindo ActivatedRouteSnapshot nós temos os valores abaixo:
Podemos trabalhar com esses dados dentro do método canActivateChild, basta você utilizar as duas variáveis criadas route e state.
Abaixo você tem um exemplo onde eu adicionei um console com o valor console.log(route.params) dentro do método canActivateChild.

Bem simples, né? Com isso finalizamos a primeira parte desse artigo sobre Guards, no próximo irei demonstrar o CanDeactivate e CanLoad. Espero que tenham gostado e até um próximo artigo, pessoal!