Desenvolvimento

20 ago, 2018

Angular 6: Route Guards

Publicidade

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.

Angular (canActivate)

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:

CanActivate

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.

CanActivate

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:

(CanActivateChild)

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:

(CanActivateChild)

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.

CanActivateChild (ActivatedRouteSnapshot,RouterStateSnapshot)

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.

retorno console.log(route.params)

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!