Jour 3 — State Management, Formulaires & Sécurité

State Management, Formulaires & Sécurité

Objectif : structurer l’état global proprement, concevoir des formulaires avancés et sécuriser l’application avec JWT, Guards et bonnes pratiques modernes Angular + Spring Boot.

RxJS & Signals NgRx / Store Pattern Reactive Forms JWT & Guards

Objectifs pédagogiques du Jour 3

Ce module consolide la partie “mécanique” d’une application professionnelle : comment l’état est stocké, comment l’utilisateur interagit via les formulaires, et comment l’accès est sécurisé.

Résultats attendus

À la fin du jour 3, vous serez capable de :

  • Choisir une stratégie de gestion d’état adaptée à votre contexte (Signals, RxJS, NgRx).
  • Concevoir des formulaires complexes, robustes et orientés UX.
  • Mettre en place une authentification JWT sécurisée côté Angular + Spring Boot.
Gains business & techniques

Impact sur vos projets

  • Réduction de la dette technique liée au “state bricolé partout”.
  • Moins de bugs fonctionnels sur les formulaires (validation cohérente, claire).
  • Sécurité renforcée sans complexifier inutilement le code.

1. Gestion d’État Réactive (RxJS, NgRx, Signals)

L’état mal géré est une source majeure de bugs et de régressions. L’objectif : arrêter de diffuser des BehaviorSubject partout et structurer un vrai state management.

Scénario simple

State local avec Signals (Angular moderne)

Idéal pour une feature isolée (catalogue, panier, écran spécifique) : lisible, local, facile à tester.


// Store local de panier basé sur Signals
@Injectable({ providedIn: 'root' })
export class CartStore {
  readonly items = signal<Product[]>([]);

  readonly total = computed(
    () => this.items().reduce((acc, p) => acc + p.price, 0)
  );

  add(product: Product) {
    this.items.update(items => [...items, product]);
  }

  clear() {
    this.items.set([]);
  }
}
Gains :
  • Aucun subscribe() à gérer → moins de fuites mémoire.
  • Debug très simple : un seul point d’entrée pour l’état.
  • Plus lisible qu’un mélange Observables/Subjects improvisés.
Cas applicatif large

NgRx / Store global pour les gros projets

Pour les applications avec beaucoup d’écrans, de rôles et de règles métier, un Store global reste pertinent.


// Exemple d'action NgRx
export const addItemToCart = createAction(
  '[Cart] Add Item',
  props<{ product: Product }>()
);

// Exemple de reducer
const reducer = createReducer(
  initialState,
  on(addItemToCart, (state, { product }) => ({
    ...state,
    items: [...state.items, product]
  }))
);
Bon réflexe : exposez le store via un service “Facade” (ex : CartFacade) pour ne pas coupler vos composants directement à NgRx.
À éviter absolument :
  • Un mélange ad hoc : un peu de Subject, un peu de store, un peu de localStorage
  • Du state global pour tout (inclus des infos qui pourraient rester locales au composant).
  • Des selectors qui contiennent de la logique métier complexe (la sortir dans des services).

2. Formulaires Complexes & UX Pro

L’utilisateur peut pardonner une erreur d’affichage, beaucoup moins un formulaire qui se comporte mal. Ici, on structure des Reactive Forms robustes.

Structure

Formulaire de commande (formulaire imbriqué)


this.orderForm = this.fb.group({
  customer: ['', Validators.required],
  email: ['', [Validators.required, Validators.email]],
  address: this.fb.group({
    street: ['', Validators.required],
    city: ['', Validators.required],
    zip: ['', Validators.required]
  }),
  acceptTerms: [false, Validators.requiredTrue]
});
Astuce : regroupez les champs liés dans des FormGroup (adresse, infos de paiement, etc.), cela simplifie la validation et la lecture.
Validation avancée

Validation croisée & logique dynamique


// Validator croisé (ex: confirmation d'email)
export function emailsMatch(group: AbstractControl) {
  const email = group.get('email')?.value;
  const confirm = group.get('confirmEmail')?.value;
  return email && confirm && email !== confirm ? { emailsMismatch: true } : null;
}

// Écoute des changements
this.orderForm.valueChanges.subscribe(value => {
  // adapter dynamiquement les options de livraison, par ex.
});
Bonnes pratiques :
  • Externaliser les validators dans des fichiers dédiés.
  • Rendre les messages d’erreur explicites et humains.
  • Préférer Reactive Forms dès qu’il y a du métier ou des règles évolutives.

3. Sécurité & Authentification côté Angular

L’authentification ne se limite pas à “vérifier si un token existe”. Il s’agit de protéger les routes, filtrer les appels et gérer les rôles correctement.

HTTP

Injection du JWT via un HttpInterceptor


@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private auth: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const token = this.auth.getToken();
    if (!token) return next.handle(req);

    const cloned = req.clone({
      setHeaders: { Authorization: `Bearer ${token}` }
    });

    return next.handle(cloned);
  }
}
Astuce : centraliser ici tous les headers communs (langue, correlation-id, etc.) au lieu de répéter dans chaque service.
Routes

Protection des routes avec un Guard


@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(private auth: AuthService, private router: Router) {}

  canActivate(): boolean {
    if (!this.auth.isLoggedIn()) {
      this.router.navigate(['/login']);
      return false;
    }
    return true;
  }
}
Pattern : Role-Based Access Control (RBAC) + Guards → règles de sécurité centralisées, simples à tester.

4. Authentification JWT côté Spring Boot

Spring Boot s’occupe de l’authentification, de la génération et de la validation du token. Angular consomme simplement l’API exposée.

Login

Endpoint d’authentification


@RestController
@RequestMapping("/api/auth")
public class AuthController {

  private final AuthService service;

  @PostMapping("/login")
  public ResponseEntity<TokenResponse> login(@RequestBody LoginRequest req) {
    return ResponseEntity.ok(service.authenticate(req));
  }
}
Bonnes pratiques

Points de vigilance côté backend

  • Limiter la durée de vie des tokens (access token court, refresh token dédié).
  • Ne jamais mettre d’information sensible en clair dans le JWT.
  • Protéger les endpoints d’admin par rôle et non uniquement par présence du token.
Important : si possible, préférer les cookies HTTPOnly pour le stockage des tokens plutôt que localStorage (protection XSS).
Jour 3 terminé — Prochaine étape : Jour 4, Tests, Performance & CI/CD Production.

Review My Order

0

Subtotal