Sécurité Spring Boot & JWT

Architecture de sécurité moderne : filtres stateless, JWT signé, refresh tokens, Spring Security 6, UserDetailsService propre, RBAC & bonnes pratiques industrielles.

Introduction

Spring Security est la référence pour sécuriser une API Spring Boot. Depuis la version 6, la configuration repose sur une approche 100% déclarative : SecurityFilterChain, stateless session, Bearer token, et JWT signé pour des API modernes et scalables.

Ce chapitre vous guide vers une implémentation professionnelle : architecture, filtres, tokens courts, refresh tokens sécurisés, rôles & permissions, logs, gestion des erreurs et bonnes pratiques.

Lexique essentiel

JWT
Token signé contenant l’identité et les rôles.
SecurityFilterChain
Chaîne de filtres qui sécurise les requêtes HTTP.
AuthenticationManager
Responsable de l’authentification.
UserDetailsService
Charge l’utilisateur depuis la base.
BCrypt
Algorithme de hachage sécurisé pour les mots de passe.
Stateless
Aucune session serveur → token nécessaire à chaque requête.

1. Configuration Spring Security 6 (stateless)


@Configuration
@EnableMethodSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http,
                                           JwtFilter jwtFilter) throws Exception {

        return http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/auth/**").permitAll()
                .anyRequest().authenticated())
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
    }
}
    

👉 Stateless obligatoire pour les API modernes. 👉 Les routes /auth/** sont ouvertes pour le login & refresh. 👉 Le filtre JWT analyse chaque requête.

2. DTO d’authentification propre


public record LoginRequest(String email, String password) {}
public record AuthResponse(String token, String refreshToken) {}
    

3. Service utilisateur — niveau pro


@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

    private final UserRepository repo;

    @Override
    public UserDetails loadUserByUsername(String email) {
        return repo.findByEmail(email)
            .map(UserPrincipal::new)
            .orElseThrow(() -> new UsernameNotFoundException("User not found"));
    }
}
    

Le UserPrincipal encapsule rôles et permissions pour la sécurité.

4. Génération du JWT signé (token court)


@Component
@RequiredArgsConstructor
public class JwtService {

    @Value("${app.jwt.secret}")
    private String secret;

    public String generateToken(UserDetails user) {
        return Jwts.builder()
            .setSubject(user.getUsername())
            .claim("roles", user.getAuthorities())
            .setExpiration(Date.from(Instant.now().plusSeconds(900))) // 15 min
            .signWith(Keys.hmacShaKeyFor(secret.getBytes()), SignatureAlgorithm.HS256)
            .compact();
    }
}
    

👉 Les tokens doivent être courts (10–20 min). 👉 Un refresh token gère la reconnexion sécurisée.

5. Le filtre JWT stateless


@Component
@RequiredArgsConstructor
public class JwtFilter extends OncePerRequestFilter {

    private final JwtService jwtService;
    private final CustomUserDetailsService userService;

    @Override
    protected void doFilterInternal(HttpServletRequest req,
                                    HttpServletResponse res,
                                    FilterChain chain)
                                    throws ServletException, IOException {

        String header = req.getHeader("Authorization");
        if (header == null || !header.startsWith("Bearer ")) {
            chain.doFilter(req, res);
            return;
        }

        String token = header.substring(7);
        String email = jwtService.extractUsername(token);

        UserDetails user = userService.loadUserByUsername(email);
        UsernamePasswordAuthenticationToken auth =
            new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());

        SecurityContextHolder.getContext().setAuthentication(auth);
        chain.doFilter(req, res);
    }
}
    

Ce filtre exécute l’authentification sur chaque requête — modèle stateless.

Bonnes pratiques :
  • Token très court + refresh token long stocké côté client.
  • Mot de passe haché via BCrypt.
  • Ne jamais stocker un JWT dans localStorage (XSS).
  • Aucune session → 100% stateless.
  • Endpoints versionnés : /api/v1/**

2. Refresh Token sécurisé (niveau entreprise)

Le refresh token permet de ré-obtenir un JWT sans forcer l’utilisateur à se reconnecter. Il doit être : long, sécurisé, stocké HTTP Only et renouvelé périodiquement.

Exemple d’implémentation


@PostMapping("/refresh")
public AuthResponse refresh(@CookieValue("refresh") String refreshToken) {
    var email = jwtService.verifyRefresh(refreshToken);
    var user = userService.loadUserByUsername(email);
    return new AuthResponse(
        jwtService.generateToken(user),
        jwtService.generateRefreshToken(email)
    );
}
    

👉 Le refresh **ne doit jamais transiter dans le body** → cookie HttpOnly obligatoire. 👉 Rotation des refresh tokens : un nouveau est généré à chaque utilisation.

Quiz : Sécurité Spring Boot

  • Q1. Quel mode est recommandé pour les API modernes ?
    • A. Stateful
    • B. Stateless ✔
    • C. Session redis
  • Q2. Où doit être stocké un refresh token ?
    • A. localStorage
    • B. Cookie HttpOnly ✔
    • C. Header

Exercice d’application

Implémentez une sécurité complète pour votre API :
— Login + token court
— Refresh token HttpOnly
— Endpoints sécurisés + RBAC (@PreAuthorize)
— Logging de sécurité
— Rotation des refresh tokens

Résumé

Spring Security & JWT permettent de construire une architecture d’authentification moderne, robuste et scalable. Le modèle stateless, couplé à un token court et un refresh token sécurisé, garantit performance, sécurité et simplicité opérationnelle.

Navigation de la Formation

Review My Order

0

Subtotal