Chapitre 1: Introduction à Spring Security
Introduction
Avant de configurer quoi que ce soit, il est essentiel de comprendre comment Spring Security fonctionne. Ce chapitre pose les fondations qui vous permettront de configurer la sécurité correctement.
🎯 Objectifs du Chapitre
À la fin de ce chapitre, vous saurez:
- ✅ Pourquoi la sécurité est essentielle
- ✅ La différence entre Authentication et Authorization
- ✅ L'architecture de Spring Security
- ✅ Comment fonctionne la chaîne de filtres
- ✅ Les concepts clés: Principal, Credentials, Authorities
1. Pourquoi Sécuriser une Application?
Les Menaces
Exemples Réels
| Année | Entreprise | Impact |
|---|---|---|
| 2023 | MOVEit | 60M+ utilisateurs touchés |
| 2021 | 533M comptes exposés | |
| 2019 | Capital One | 100M+ données volées |
| 2017 | Equifax | 147M données personnelles |
Les 3 Piliers de la Sécurité (CIA)
┌─────────────────────────────────────────────────┐
│ │
│ C - Confidentialité │
│ Seules les personnes autorisées │
│ peuvent voir les données │
│ │
│ I - Intégrité │
│ Les données ne peuvent pas être │
│ modifiées sans autorisation │
│ │
│ A - Disponibilité │
│ Le système reste accessible │
│ aux utilisateurs légitimes │
│ │
└─────────────────────────────────────────────────┘
2. Authentication vs Authorization
La Différence Fondamentale
| Concept | Question | Exemple |
|---|---|---|
| Authentication | "Qui êtes-vous?" | Login avec email/mot de passe |
| Authorization | "Avez-vous le droit?" | Accéder à /admin (réservé aux admins) |
Analogie: Le Club VIP
En Spring Security
// Authentication: Qui est connecté?
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName(); // "jean@example.com"
// Authorization: Quels sont ses droits?
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
// [ROLE_USER] - Pas ROLE_ADMIN!
3. Architecture de Spring Security
Vue d'Ensemble
Les Composants Clés
1. SecurityFilterChain
La chaîne de filtres qui intercepte TOUTES les requêtes:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.build();
}
}
2. AuthenticationManager
Coordonne l'authentification:
3. UserDetailsService
Interface pour charger les utilisateurs:
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
4. PasswordEncoder
Encode les mots de passe (JAMAIS en clair!):
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// Utilisation
String encoded = passwordEncoder.encode("monMotDePasse");
// $2a$10$N9qo8uLOickgx2ZMRZoMye...
boolean matches = passwordEncoder.matches("monMotDePasse", encoded);
// true
4. La Chaîne de Filtres en Détail
Ordre des Filtres (Simplifié)
1. CorsFilter → Gestion CORS
2. CsrfFilter → Protection CSRF
3. LogoutFilter → Gestion déconnexion
4. UsernamePasswordAuthFilter → Login par formulaire
5. BasicAuthenticationFilter → HTTP Basic Auth
6. BearerTokenAuthFilter → JWT/OAuth2
7. AnonymousAuthenticationFilter → Utilisateur anonyme
8. ExceptionTranslationFilter → Gestion des erreurs
9. FilterSecurityInterceptor → Décision d'accès finale
Visualisation du Flow
5. Concepts Clés
Principal
L'identité de l'utilisateur connecté:
@GetMapping("/profile")
public String profile(Principal principal) {
String username = principal.getName();
return "Bienvenue " + username;
}
Authentication Object
Contient toutes les informations d'authentification:
public interface Authentication {
Collection<? extends GrantedAuthority> getAuthorities(); // Rôles/Permissions
Object getCredentials(); // Mot de passe (souvent effacé après auth)
Object getDetails(); // Détails additionnels (IP, etc.)
Object getPrincipal(); // L'utilisateur (UserDetails)
boolean isAuthenticated();
}
GrantedAuthority
Représente un rôle ou une permission:
// Rôles (préfixe ROLE_)
new SimpleGrantedAuthority("ROLE_ADMIN");
new SimpleGrantedAuthority("ROLE_USER");
// Permissions
new SimpleGrantedAuthority("READ_USERS");
new SimpleGrantedAuthority("WRITE_USERS");
new SimpleGrantedAuthority("DELETE_USERS");
SecurityContext
Stocke l'Authentication de l'utilisateur courant:
// Récupérer l'utilisateur connecté
SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
if (auth != null && auth.isAuthenticated()) {
String username = auth.getName();
// ...
}
UserDetails
Interface représentant un utilisateur:
public interface UserDetails {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
6. Types d'Authentification
1. Form Login (Session)
Client → POST /login (user, pass)
Server → Set-Cookie: JSESSIONID=xyz
Client → GET /api/data (Cookie: JSESSIONID=xyz)
Server → Vérifie session → 200 OK
Avantages: Simple, géré par le navigateur Inconvénients: Pas adapté aux API REST stateless
2. HTTP Basic
Client → GET /api/data
Server → 401 + WWW-Authenticate: Basic
Client → GET /api/data (Authorization: Basic base64(user:pass))
Server → 200 OK
Avantages: Simple Inconvénients: Credentials envoyés à chaque requête
3. JWT (Token)
Client → POST /login (user, pass)
Server → {"token": "eyJhbGciOiJIUzI1..."}
Client → GET /api/data (Authorization: Bearer eyJhbGciOiJIUzI1...)
Server → Vérifie token → 200 OK
Avantages: Stateless, parfait pour API REST Inconvénients: Gestion de l'expiration
4. OAuth2
Client → Redirect vers Google
Google → Login utilisateur
Google → Redirect avec code
Server → Échange code contre token
Server → Récupère profil utilisateur
Avantages: Pas de mot de passe à gérer, UX moderne Inconvénients: Dépendance externe
7. Configuration Moderne (Spring Security 6+)
Ancienne Méthode (Déprécié)
// ❌ NE PLUS UTILISER
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
}
}
Nouvelle Méthode (Spring Security 6+)
// ✅ UTILISER CETTE APPROCHE
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
8. Première Configuration
Dépendance Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Comportement par Défaut
Sans aucune configuration, Spring Security:
- Protège TOUS les endpoints
- Génère un mot de passe aléatoire (affiché dans les logs)
- Active le form login sur
/login - Active le logout sur
/logout
Using generated security password: 8e3d7a2c-1234-5678-abcd-ef0123456789
Configuration Minimale
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/home", "/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout
.permitAll()
)
.build();
}
}
9. Résumé
Concepts Clés
| Concept | Description |
|---|---|
| Authentication | Vérifier l'identité (qui?) |
| Authorization | Vérifier les droits (quoi?) |
| SecurityFilterChain | Chaîne de filtres de sécurité |
| AuthenticationManager | Orchestre l'authentification |
| UserDetailsService | Charge les utilisateurs |
| PasswordEncoder | Encode les mots de passe |
| SecurityContext | Stocke l'utilisateur courant |
Architecture Simplifiée
Requête HTTP
↓
SecurityFilterChain (filtres)
↓
AuthenticationManager
↓
UserDetailsService + PasswordEncoder
↓
SecurityContext (stockage)
↓
Application (Controller)
Points Importants
✅ Spring Security 6+ utilise des @Bean, pas extends WebSecurityConfigurerAdapter
✅ Toujours encoder les mots de passe (BCrypt)
✅ Comprendre Authentication vs Authorization
✅ La sécurité se configure via SecurityFilterChain
🎯 Prochaine Étape
Maintenant que vous comprenez l'architecture, passons à la pratique avec l'authentification basique.
➡️ Chapitre 2: Authentification Basique