Route Guards em Angular
Os Route Guards (guardas de rota) são recursos do Angular que permitem controlar a navegação em rotas. Eles fornecem uma maneira de proteger e controlar o acesso a rotas, permitindo tomar decisões antes de carregar uma rota, como verificar autenticação, permissões, entre outras lógicas de autorização.
Criando um Guard
ng g guard nome_da_guard
Ao executar o comando, irá perguntar qual o método de verificação, aqui se deve escolher CanActivate.
No Angular 17, a forma como se gerencia um Guard, por padrão, mudou. Antes o que seria uma classe que implementa CanActivate Agora é so uma função do tipo CanActivateFn, sendo agora uma função, para injetar dependências dentro do Guard, se usa o inject que vem do @angular/core
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
export const guardTestGuard: CanActivateFn = (route, state) => {
const router = inject(Router)
return true;
};
Antes, os Guards se pareciam com isso:
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AutorizadoGuard implements CanActivate {
constructor(private routerService: Router){}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
}
Como o Guard atua
Antes do usuário conseguir entrar em uma página, caso tenha um Guard naquela rota, o Guard será acionado e baseado na lógica construída nele, irá permitir ou não que o usuário consiga entrar naquela página, uma Gaurd retorna um valor booleano.
Para incluir um Guard em uma rota, é necessário declarar o Guard nele, ou seja, no arquivo de rotas da aplicação, rotas já foram abordadas anteriormente, inclua a propriedade CanActivate que esperará um array de Guard. Por aguardar um array, já é possível concluir que podem ter vários Guards por rota.
import NomeDoGuard from "caminho/do/Guard";
export const routes: Routes = [
{path:'pg1', component:Pg1Component, canActivated: [NomeDoGuard]}
];
Dentro de um guard é possível fazer requisições para API, a fim de validar se o usuário tem autorização para acessar aquela página, ou só acessar os cookies do navegador e verificar se existe um cookie de sessão ativo.
Usando Guard em várias rotas
Por padrão, o Guard precisa ser incluído em todas as rotas que usam ele, isso pode ser maçante se a aplicação possuir várias rotas, para resolver esse problema, é possível se aproveitar das rotas alinhadas explicadas no tópico de rotas, usando o exemplo que foi usado para a explicação do Layout padrão, ficaria assim:
const routes: Routes = [
{
path: '',
component: LayoutComHeaderComponent,
canActivate: [AuthGuard] //Apenas essas rotas tem Guard
children: [
{ path: 'pagina1', component: Pagina1Component },
{ path: 'pagina2', component: Pagina2Component },
// ... outras rotas com Guard...
]
},
{ path: 'login', component: LoginComponent }, // Rota sem Guard
{ path: 'logout', component: LogoutComponent }, // Rota sem Guard
{ path: '404', component: NotFoundComponent }, // Rota sem Guard
];
Dessa forma, é possível escolher quais rotas precisam de validação de usuário e quais não precisam.
Exemplo de Uso
Será criado um Guard para verificar se existe um item token, válido, no LocalStorage do navegador e se sim o Guard passará, se não, o Guard precisa redirecionar o usuário para a página de login.
AuthService
Primeiro, vamos criar um serviço de autenticação AuthService que verifica se o token está presente e se é válido.
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class AuthService {
getToken(): string | null {
return localStorage.getItem('token');
}
isLoggedIn(): boolean {
const token = this.getToken();
return !!token; // Retorna true se o token existir
}
}
Implementando o Route Guard:
Agora, vamos criar um Guard (AuthGuard) que utiliza o serviço AuthService para verificar se o token está presente e se é válido.
export const guardTestGuard: CanActivateFn = (route, state) => {
const router = inject(Router)
const authService = inject(AuthService)
if (this.authService.isLoggedIn()) {
return true; // O usuário pode acessar a rota
} else {
this.router.navigate(['/login']); // Redireciona para a página de login se não estiver autenticado
return false; // Não permite o acesso à rota
}
};
Configuração nas Rotas:
Finalmente, configure o AuthGuard nas suas rotas que exigem autenticação.
const routes: Routes = [
//{...}
{
path: 'home',
component: HomeComponent,
canActivate: [guardTestGuard] // Protege a rota com o AuthGuard
},
// ... outras rotas protegidas ...
];