Salta el contingut

drawing

🚀 Guia Pas a Pas: Implementació de Login amb Angular i JWT

Aquesta guia explica detalladament com crear des de zero una aplicació Angular que implementi autenticació mitjançant JWT (JSON Web Token), utilitzant les millors pràctiques d'Angular 17+ (Standalone Components, Signals, Interceptors).

Requisits Previs

  • Node.js instal·lat (v18.13 o superior recomanat).
  • Coneixements bàsics de TypeScript i HTML/CSS.
  • Una API Backend funcionant que retorni un JWT (com la del projecte servidor).

1. Creació del Projecte

El primer pas és generar una nova aplicació Angular. Utilitzarem l'opció --no-standalone si volem mòduls o, com recomanem ara, per defecte (Standalone).

ng new client-angular --style=scss --routing
cd client-angular

Estructura de Carpetes

Organitza el teu codi des del principi. Recomanem aquesta estructura dins de src/app/:

  • components/: Vistes (Login, Users, etc.)
  • services/: Lògica de negoci i HTTP.
  • models/: Interfícies TypeScript.
  • interceptors/: Manipulació global de peticions.
  • guards/: Protecció de rutes.

2. Instal·lació de Llibreries UI (Opcional però Recomanat)

Per tenir una interfície professional ràpidament, instal·lem Angular Material.

ng add @angular/material
  • Tria un tema (ex: "Deep Purple/Amber" o "Custom").
  • Accepta les tipografies i animacions globals.

3. Definició de Models (TypeScript)

Abans de programar lògica, definim què estem movent. Crea src/app/models/user.model.ts.

ng g m models/user
export interface User {
  id: number;
  username: string;
  email: string;
}

export interface LoginRequest {
  username: string;
  password: string;
}

export interface JwtResponse {
  token: string;
  message?: string;
}

4. Implementació de Serveis (La Lògica)

4.1. AuthService

Aquest servei gestionarà l'estat de l'usuari i el localStorage.

ng g s services/auth
// src/app/services/auth.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, tap } from 'rxjs';
import { LoginRequest, JwtResponse } from '../models/user.model';

@Injectable({ providedIn: 'root' })
export class AuthService {
  private http = inject(HttpClient);
  private apiUrl = 'http://localhost:8080/api/auth'; // Ajusta al teu backend

  // Gestiona l'estat: Estic loguejat? Qui sóc?
  private currentUserSubject = new BehaviorSubject<string | null>(localStorage.getItem('token'));
  public currentUser$ = this.currentUserSubject.asObservable();

  login(credentials: LoginRequest) {
    return this.http.post<JwtResponse>(`${this.apiUrl}/login`, credentials).pipe(
      tap(response => {
        // Guardem al navegador i notifiquem a l'app
        localStorage.setItem('token', response.token);
        this.currentUserSubject.next(response.token);
      })
    );
  }

  logout() {
    localStorage.removeItem('token');
    this.currentUserSubject.next(null);
  }

  isLoggedIn(): boolean {
    return !!localStorage.getItem('token');
  }
}

5. Components: Login UI

Crea el component de login: ng g c components/login.

LoginComponent (Lògica .ts)

@Component({
//... imports: [MatCardModule, MatInputModule, FormsModule, ReactiveFormsModule]
standalone: true,
//...
})
export class LoginComponent {
private authService = inject(AuthService);
private router = inject(Router);

  credentials = { username: '', password: '' };

  onSubmit() {
    this.authService.login(this.credentials).subscribe({
      next: () => this.router.navigate(['/users']),
      error: (err) => console.error('Error de login', err)
    });
  }
}

El template HTML hauria de tenir un formulari que faci servir [(ngModel)] o formControl per lligar les dades amb credentials.


6. La Seguretat: Interceptor HTTP

Com enviem el token automàticament? No l'afegeixis manualment a cada petició. Fes servir un Interceptor.

// src/app/interceptors/auth.interceptor.ts
import { HttpInterceptorFn } from '@angular/common/http';

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = localStorage.getItem('token');

  if (token) {
    // Clonem la petició perquè són immutables
    const cloned = req.clone({
      setHeaders: {
        Authorization: `Bearer ${token}`
      }
    });
    return next(cloned);
  }

  return next(req);
};

Important: Registra'l a app.config.ts:

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withInterceptors([authInterceptor]))
    // ... altres providers
  ]
};

7. Protecció de Rutes: Guards

Volem prohibir l'entrada a /users si no estàs loguejat.

// src/app/guards/auth.guard.ts
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
import { AuthService } from '../services/auth.service';

export const authGuard: CanActivateFn = (route, state) => {
  const authService = inject(AuthService);
  const router = inject(Router);

  if (authService.isLoggedIn()) {
    return true;
  } else {
    router.navigate(['/login']);
    return false;
  }
};

Aplica-ho a app.routes.ts:

export const routes: Routes = [
  { path: 'login', component: LoginComponent },
  { path: 'users', component: UsersComponent, canActivate: [authGuard] },
  { path: '', redirectTo: '/login', pathMatch: 'full' }
];

8. Resum del Flux

  1. L'usuari entra a /login ➡️ Introdueix dades.
  2. AuthService envia POST al backend.
  3. Si és OK, guarda el token a localStorage.
  4. L'usuari va a /users.
  5. AuthGuard comprova el token ➡️ Deixa passar.
  6. UsersComponent demana la llista d'usuaris.
  7. AuthInterceptor intercepta la petició i li posa el barret (header) del Token.
  8. El servidor valida el token i retorna les dades privades.

Felicitats!

Has implementat un sistema d'autenticació professional i segur amb Angular 17+! 🚀