Kevin Villatoro
En que clase se ve la forma correcta de guardar el token?
Cómo proteger nuestras rutas con CanActivate
// Desde la terminal creamos servicio de token y escapamos los tests ng g s services/token --skip-tests // Este servicio es el que va a persistir el token y va a escoger la estrategia adecuada para guardar el token (*) Solo en ésta clase vamos a guardar el token en el localStorage, en la siguiente clase vamos a ver cómo guardar el token de forma más segura en cookies.
// token.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class TokenService { constructor() { } saveToken(token: string) { localStorage.setItem('token', token); } getToken() { const token = localStorage.getItem('token'); return token; } removeToken() { localStorage.removeItem('token'); } }
// auth.service.ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { environment } from '@environments/environment'; import { switchMap, tap } from 'rxjs'; import { TokenService } from './token.service'; import { ResponseLogin } from '@models/auth.model'; @Injectable({ providedIn: 'root' }) export class AuthService { apiUrl = environment.API_URL; constructor( private http: HttpClient, private tokenService: TokenService ) { } login(email: string, password: string) { return this.http.post<ResponseLogin>(`${this.apiUrl}/api/v1/auth/login`, { email, password }) .pipe( tap(response => { this.tokenService.saveToken(response.access_token); }) ) } register(name: string, email: string, password: string) { return this.http.post(`${this.apiUrl}/api/v1/auth/register`, { name, email, password }); } registerAndLogin(name: string, email: string, password: string) { return this.register(name, email, password) .pipe( switchMap(() => this.login(email, password)) ) } isAvailable(email: string) { return this.http.post<{ isAvailable: boolean }>(`${this.apiUrl}/api/v1/auth/is-available`, { email }); } recovery(email: string) { return this.http.post(`${this.apiUrl}/api/v1/auth/recovery`, { email }); } changePassword(token: string, newPassword: string) { return this.http.post(`${this.apiUrl}/api/v1/auth/change-password`, { token, newPassword }) } }
// auth.model.ts export interface ResponseLogin { access_token: string; refresh_token: string; }
// Desde la terminal creamos un guardián para proteger nuestras rutas ng g g guards/auth --skip-tests // Seleccionamos el tipo CanActivate
// auth.guard.ts import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router'; import { Observable } from 'rxjs'; import { TokenService } from '@services/token.service'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { constructor( private tokenService: TokenService, private router: Router ){} canActivate(): boolean { const token = this.tokenService.getToken(); if (!token) { this.router.navigate(['/login']); return false; } return true } }
// app.routing.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AuthGuard } from '@guards/auth.guard'; const routes: Routes = [ { path: '', loadChildren: () => import('./modules/auth/auth.module').then((m) => m.AuthModule), }, { path: 'app', canActivate: [ AuthGuard ], // (*) loadChildren: () => import('./modules/layout/layout.module').then((m) => m.LayoutModule), }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } // (*) Protegiendo la ruta app, por herencia se protegen también las rutas hijas.
Para los panitas que trabajen en Angular 17, el guardian se escribe asi:
import { inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; import { TokenService } from '@services/token.service'; export const authGuard: CanActivateFn = (route, state) => { const tokenService = inject(TokenService); const router = inject(Router); const token = tokenService.getToken(); if (!token) { router.navigate(['/login']); return false; } return true; };
Para los que estén en Angular 17 o 18, solo tienen que importar el guard en la ruta del componente que quieran proteger.
Kevin Villatoro
En que clase se ve la forma correcta de guardar el token?
Josué Eliezer Gómez Soto
Me aparece que el CANACTIVATE ya esta marcado como obsoleto, alguien sabe como es la implementación de ello ahora?
Roger Chung
Nicolas, que pasa si alguien guarda un token de otro usuario? cuando se hace la verificacion del token si realmente le pertenece al usuario?
Jose Armando Acevedo Angarita
Nicolas, pero al usar el canActivate en el modulo se llama tantas veces dependiendo del numero de componentes que se llamen en su routing, no es mejor hacerlo desde el routing de layout y en el path donde llama al componente de layout?
Jose Armando Acevedo Angarita
Lo digo porque una vez hice un servicio de permisos y el que llamaba el servicio era el guardián y ejecutaba el método unas 8 veces porque tenía 8 módulos más dentro del módulo de donde lo llamaba
Jean Michael Lozano Cardoso
Esa es la idea, que no te cargue ningun componente si no tiene permisos para ese modulo. La validación debe ser desde el papá (el modulo), no en los hijos.