web:framework:spring:security

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
web:framework:spring:security [2023/12/05 11:07] – [Mise en place CSRF] jcheronweb:framework:spring:security [2026/10/26 11:24] (Version actuelle) – [Mise en place CSRF] jcheron
Ligne 1: Ligne 1:
 ====== Spring security ====== ====== Spring security ======
  
-Spring Sécurity est un framework permettant d'ajouter aux applications Spring authentification et contrôle d'accès.+Spring Security est un framework permettant d'ajouter aux applications Spring authentification et contrôle d'accès.
  
 Spring security ajoute au Dispatcher servlet de Spring MVC un ensemble de filtres (servlet filters) qualifié de **filter chain**. Spring security ajoute au Dispatcher servlet de Spring MVC un ensemble de filtres (servlet filters) qualifié de **filter chain**.
Ligne 7: Ligne 7:
 ===== Intégration ===== ===== Intégration =====
  
-Ajouter les dépendances suivantes à **pom.xml** :+Ajouter la dépendance suivante à **pom.xml** :
  
 <sxh xml;title:pom.xml> <sxh xml;title:pom.xml>
- <dependency> +<dependency> 
-     <groupId>org.springframework.security</groupId> +    <groupId>org.springframework.boot</groupId> 
-     <artifactId>spring-security-web</artifactId> +    <artifactId>spring-boot-starter-security</artifactId> 
- </dependency> +</dependency>
- +
- <dependency> +
-     <groupId>org.springframework.security</groupId> +
-     <artifactId>spring-security-test</artifactId> +
-     <scope>test</scope> +
- </dependency> +
-  +
- <dependency> +
-     <groupId>org.springframework.security</groupId> +
-     <artifactId>spring-security-config</artifactId> +
- </dependency>+
 </sxh> </sxh>
  
 ===== Authentification par défaut ===== ===== Authentification par défaut =====
  
-L'intégration de Spring security met en place une authentification basique par défaut, avec un utilisateur de non **user**, ayant le rôle **USER**, \\+L'intégration de Spring security met en place une authentification basique par défaut, avec un utilisateur de nom **user**, ayant le rôle **USER**, \\
 dont le password s'affiche dans la console de démarrage de Spring, utilisable en mode développement : dont le password s'affiche dans la console de démarrage de Spring, utilisable en mode développement :
  
Ligne 38: Ligne 27:
 Il est possible de modifier l'utilisateur par défaut dans **application.properties** : Il est possible de modifier l'utilisateur par défaut dans **application.properties** :
  
-<sxh ;title:application.properties>+<sxh ini;title:application.properties>
 spring.security.user.name=boris spring.security.user.name=boris
 spring.security.user.password=boris-password spring.security.user.password=boris-password
Ligne 47: Ligne 36:
 La configuration se fait au travers d'une classe de configuration activant la sécurité : La configuration se fait au travers d'une classe de configuration activant la sécurité :
  
-<sxh java;title:WebSecurityConfig>+<sxh java;title:SecurityConfig>
 @Configuration @Configuration
 @EnableWebSecurity @EnableWebSecurity
-public class WebSecurityConfiguration {+public class SecurityConfig {
  
     @Bean     @Bean
-    public SecurityFilterChain configure(HttpSecurity http) throws Exception { +    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 
-        http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests( +        http.authorizeHttpRequests(req -> req 
-                        (req) -> req.requestMatchers( +                .requestMatchers("/", "/css/**", "/js/**", "/img/**", "/register/**").permitAll() 
-                                        AntPathRequestMatcher.antMatcher("/"), +                .anyRequest().authenticated() 
-                                        AntPathRequestMatcher.antMatcher("/css/**"), +        );
-                                        AntPathRequestMatcher.antMatcher("/js/**"), +
-                                        AntPathRequestMatcher.antMatcher("/img/**"), +
-                                        AntPathRequestMatcher.antMatcher("/register/**") +
-                                ) +
-                                .permitAll() +
-                                .anyRequest() +
-                                .authenticated() +
-                ).formLogin();+
         return http.build();         return http.build();
     }     }
 } }
 </sxh> </sxh>
 +
 +<wrap info round>
 +Les chaînes passées à **requestMatchers** sont interprétées comme des patterns de chemin. Il n'est plus nécessaire d'utiliser **AntPathRequestMatcher** (déprécié dans les versions récentes).
 +</wrap>
 +
 +<wrap important round>
 +La protection CSRF est **activée par défaut**. Ne la désactivez pas (**csrf.disable()**) sans raison valable, voir la section [[#mise_en_place_csrf|Mise en place CSRF]].
 +</wrap>
 +
 ===== Authentification depuis une BDD ===== ===== Authentification depuis une BDD =====
  
 ==== Entity ==== ==== Entity ====
  
-Créer ou reprendre votre entity **User** pour gérer les utilisateurs et leur rôle :+Créer ou reprendre votre entity **User** pour gérer les utilisateurs et leur rôle.
  
 Elle devra implémenter l'interface **UserDetails** : Elle devra implémenter l'interface **UserDetails** :
  
 <sxh java;title:User> <sxh java;title:User>
 +@Entity
 public class User implements UserDetails { public class User implements UserDetails {
     @Id     @Id
Ligne 95: Ligne 86:
     @ManyToOne     @ManyToOne
     private Role role;     private Role role;
-    +
     @Override     @Override
     public Collection<? extends GrantedAuthority> getAuthorities() {     public Collection<? extends GrantedAuthority> getAuthorities() {
Ligne 129: Ligne 120:
         return true;         return true;
     }     }
 +
 +    // getters / setters ...
 } }
 </sxh> </sxh>
  
-Créer le repository associé et ajouter une méthode permettant de rechercher un User par son username ou son email :+Créer le repository associé et ajouter une méthode permettant de rechercher un User par son login ou son email :
  
 <sxh java;title:UserRepository> <sxh java;title:UserRepository>
Ligne 142: Ligne 135:
 ==== UserDetailsService ==== ==== UserDetailsService ====
  
-Créer un Service implémentant **UserDetailsService** :+Créer un Service implémentant **UserDetailsService**.
  
-Ce service retourne depuis la base de données un utilisateur recherché par son nom ou son email et retourne une instance de **UserDetails** :+Ce service retourne depuis la base de données un utilisateur recherché par son login ou son email, sous la forme d'une instance de **UserDetails** :
  
-<sxh java;title:DbUserService>+<sxh java;title:UserService>
 @Service @Service
 public class UserService implements UserDetailsService { public class UserService implements UserDetailsService {
  
-    @Autowired +    private final UserRepository uRepo; 
-    private UserRepository uRepo;+    private final RoleRepository rRepo; 
 +    private final PasswordEncoder pEncoder;
  
-    @Autowired +    public UserService(UserRepository uRepo, RoleRepository rRepo, PasswordEncoder pEncoder) { 
-    private RoleRepository rRepo; +        this.uRepo = uRepo; 
- +        this.rRepo = rRepo; 
-    @Autowired +        this.pEncoder = pEncoder; 
-    private PasswordEncoder pEncoder;+    }
  
     @Override     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
-        Optional<User> optUser = uRepo.findByLoginOrEmail(username, username); +        return uRepo.findByLoginOrEmail(username, username) 
-        return optUser.orElseThrow(() -> new UsernameNotFoundException("Utilisateur inconnu"));+                .orElseThrow(() -> new UsernameNotFoundException("Utilisateur inconnu"));
     }     }
  
Ligne 170: Ligne 164:
 } }
 </sxh> </sxh>
 +
 +<wrap info>
 +Préférez l'**injection par constructeur** à **@Autowired** sur les champs : elle facilite les tests et évite les dépendances cachées.
 +</wrap>
  
 ==== Password encoder ==== ==== Password encoder ====
  
-Modifier la configuration de spring security pour définir le hashage du mot de passe (Bcrypt) : +Déclarer dans la configuration un **PasswordEncoder** (hashage Bcrypt) : 
-<sxh java;title:WebSecurityConfig>+ 
 +<sxh java;title:SecurityConfig>
 @Configuration @Configuration
 @EnableWebSecurity @EnableWebSecurity
-public class WebSecurityConfiguration {+public class SecurityConfig {
  
     @Bean     @Bean
-    public SecurityFilterChain configure(HttpSecurity http) throws Exception {+    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
         ...         ...
         return http.build();         return http.build();
     }     }
  
-    @Primary 
     @Bean     @Bean
-    public UserDetailsService getUserDetailsService() { +    public PasswordEncoder passwordEncoder() {
-        return new UserService(); +
-    } +
- +
-    @Bean +
-    public PasswordEncoder getPasswordEncoder() {+
         return new BCryptPasswordEncoder();         return new BCryptPasswordEncoder();
     }     }
Ligne 198: Ligne 191:
 </sxh> </sxh>
  
-<wrap important>Le **Bean** UserDetailsService est marqué comme **@Primary** pour être le premier choisi par Spring lors de l'injection.</wrap> +<wrap info> 
- +Spring Boot détecte automatiquement un bean **UserDetailsService** (ici **UserService**, déclaré via **@Service**) et un bean **PasswordEncoder**, et configure l'authentification en conséquence.\\ 
-==== Déclaration du service ==== +Il n'est donc **pas nécessaire** de déclarer manuellement un **DaoAuthenticationProvider**, ni de redéclarer **UserService** avec **@Bean** ou **@Primary**. 
- +</wrap>
-<sxh java;title:WebSecurityConfig> +
-@Configuration +
-@EnableWebSecurity +
-public class WebSecurityConfiguration { +
-    ... +
-    @Bean +
-    public DaoAuthenticationProvider authenticationProvider(UserDetailsService userService) { +
-        DaoAuthenticationProvider auth = new DaoAuthenticationProvider(); +
-        auth.setUserDetailsService(userService); +
-        auth.setPasswordEncoder(getPasswordEncoder()); +
-        return auth; +
-    } +
-} +
-</sxh>+
  
 +<wrap important round>
 +Attention aux **dépendances circulaires** : si **UserService** injecte **PasswordEncoder** et que le bean **PasswordEncoder** est défini dans une classe qui injecte **UserService**, Spring échouera au démarrage. Ici, **SecurityConfig** ne dépend pas de **UserService**, donc tout va bien.
 +</wrap>
  
 === Création d'utilisateur === === Création d'utilisateur ===
-Ne pas oublier de hasher le password User avant création :+Ne pas oublier de hasher le password du User avant création :
  
-<sxh java;title:DbUserService>+<sxh java;title:UserService>
 @Service @Service
 public class UserService implements UserDetailsService { public class UserService implements UserDetailsService {
Ligne 234: Ligne 216:
         user.setRole(getRole("ROLE_USER"));         user.setRole(getRole("ROLE_USER"));
         return uRepo.save(user);         return uRepo.save(user);
 +    }
 +}
 +</sxh>
 +
 +=== Récupération de l'utilisateur connecté ===
 +Récupération de l'utilisateur connecté en tant que **ModelAttribute** pour utilisation dans les vues :
 +
 +<sxh java;title:MainAdvice>
 +@ControllerAdvice
 +public class MainAdvice {
 +    @ModelAttribute("activeUser")
 +    public User activeUser(Authentication auth) {
 +        return (auth == null) ? null : (User) auth.getPrincipal();
     }     }
 } }
Ligne 241: Ligne 236:
  
 Créer un template pour le formulaire de connexion : Créer un template pour le formulaire de connexion :
-<sxh html;title:formLogin.html>+ 
 +<sxh html;title:loginForm.html>
 <form method="post" action="./login"> <form method="post" action="./login">
     <input type="text" name="username" placeholder="E-mail address or username">     <input type="text" name="username" placeholder="E-mail address or username">
     <input type="password" name="password" placeholder="Password">     <input type="password" name="password" placeholder="Password">
 +    <!-- Token CSRF (voir section CSRF) -->
 +    <input type="hidden" name="{{_csrf.parameterName}}" value="{{_csrf.token}}"/>
     <button type="submit">Login</button>     <button type="submit">Login</button>
 </form> </form>
 </sxh> </sxh>
  
-Ajouter une route pour le **login**+Ajouter une route pour le **login** :
  
-<sxh java:AppConfig>+<sxh java;title:WebConfiguration>
 @Configuration @Configuration
 public class WebConfiguration implements WebMvcConfigurer { public class WebConfiguration implements WebMvcConfigurer {
-   +
     @Override     @Override
     public void addViewControllers(ViewControllerRegistry registry) {     public void addViewControllers(ViewControllerRegistry registry) {
-    registry.addViewController("/login").setViewName("/forms/loginForm");+        registry.addViewController("/login").setViewName("forms/loginForm");
     }     }
 } }
 </sxh> </sxh>
  
-Modifier la configuration dans **WebSecurityConfig** :+Modifier la configuration dans **SecurityConfig** :
  
-<sxh java;title:WebSecurityConfiguration>+<sxh java;title:SecurityConfig>
 @Configuration @Configuration
 @EnableWebSecurity @EnableWebSecurity
-public class WebSecurityConfiguration {+public class SecurityConfig {
  
     @Bean     @Bean
-    public SecurityFilterChain configure(HttpSecurity http) throws Exception { +    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 
-        http.+        http
                 ...                 ...
-                .formLogin( +                .formLogin(form -> form 
-                        (form) -> form.loginPage("/login").defaultSuccessUrl("/", true).permitAll()+                        .loginPage("/login") 
 +                        .defaultSuccessUrl("/", true) 
 +                        .permitAll()
                 );                 );
         return http.build();         return http.build();
     }     }
 +}
 </sxh> </sxh>
  
 ==== Connexion à la console H2 ==== ==== Connexion à la console H2 ====
-Pour autoriser l'accès à la console h2 : +Pour autoriser l'accès à la console H2 (**uniquement en développement**) : 
-  - Désactiver la protection csrf+  - Ignorer la protection CSRF pour la console
   - Autoriser la route vers la console **/h2-console**   - Autoriser la route vers la console **/h2-console**
-  - Autoriser l'utilisation des iframes pour l'adresse locale+  - Autoriser l'utilisation des iframes pour l'origine locale
  
-<sxh java;title:WebSecurityConfig>+<sxh java;title:SecurityConfig>
 @Configuration @Configuration
 @EnableWebSecurity @EnableWebSecurity
-public class WebSecurityConfiguration {+public class SecurityConfig {
  
     @Bean     @Bean
-    public SecurityFilterChain configure(HttpSecurity http) throws Exception { +    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 
-        http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(   // (1) +        http 
-                        (req) -> req.requestMatchers( +                .csrf(csrf -> csrf.ignoringRequestMatchers(PathRequest.toH2Console()))   // (1) 
-                                        AntPathRequestMatcher.antMatcher("/h2-console/**"),   // (2) +                .authorizeHttpRequests(req -> req 
-                                        ... +                        .requestMatchers(PathRequest.toH2Console()).permitAll()          // (2) 
-                                ) +                        .requestMatchers("/", "/css/**", "/js/**").permitAll() 
-                                .permitAll() +                        .anyRequest().authenticated() 
-                                .anyRequest() +                ) 
-                                .authenticated() +                .headers(headers -> headers 
-                ).headers( +                        .frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)  // (3)
-                        (headers) -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)   // (3)+
                 );                 );
         return http.build();         return http.build();
Ligne 308: Ligne 308:
 } }
 </sxh> </sxh>
 +
 +<wrap important round>
 +La console H2 ne doit **jamais** être exposée en production. Idéalement, placez cette configuration dans un profil Spring dédié (**@Profile("dev")**).
 +</wrap>
 +
 ===== Rôles et authorities ===== ===== Rôles et authorities =====
  
-Spring Security distingue les authorities, accessible par une simple chaîne (encapsulée ensuite dans un objet de type **GrantedAuthority**) : **USER, ADMIN...**\\ +Spring Security distingue les authorities, accessibles par une simple chaîne (encapsulée ensuite dans un objet de type **GrantedAuthority**) : **USER, ADMIN...**\\ 
-et le rôle équivalent, authority préfixée par ROLE_ : **ROLE_USER, ROLE_ADMIN...**.+et le rôle équivalent, authority préfixée par **ROLE_** : **ROLE_USER, ROLE_ADMIN...**.
  
-Il est possible de faire référence à l'un ou à l'autre indiféremment.+Il est possible de faire référence à l'un ou à l'autre indifféremment, à condition de respecter le préfixe : 
 +  * **hasRole("ADMIN")** vérifie l'authority **ROLE_ADMIN** (le préfixe est ajouté automatiquement) 
 +  * **hasAuthority("ROLE_ADMIN")** vérifie la même chose, mais le préfixe doit être écrit explicitement 
 + 
 +Le rôle des utilisateurs pourra donc être stocké en base de données, sous la forme d'une chaîne, ou d'une liste de chaînes.
  
-Le rôle des utilisateurs pourra dons être stocké en base de données, sous la forme d'une chaîne, ou d'une liste de chaînes. 
 ==== Hiérarchie des authorities ==== ==== Hiérarchie des authorities ====
 Il est possible de définir les authorities de manière hiérarchique : Il est possible de définir les authorities de manière hiérarchique :
  
-<sxh java>+<sxh java;title:SecurityConfig>
     @Bean     @Bean
     static RoleHierarchy roleHierarchy() {     static RoleHierarchy roleHierarchy() {
-        RoleHierarchyImpl hierarchy = new RoleHierarchyImpl(); +        return RoleHierarchyImpl.fromHierarchy(""" 
-        hierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER"); +                ROLE_ADMIN > ROLE_REDACTOR 
-        return hierarchy;+                ROLE_REDACTOR > ROLE_USER 
 +                """);
     }     }
- 
  
     @Bean     @Bean
-    static MethodSecurityExpressionHandler methodSecurityExpressionHandler() {+    static MethodSecurityExpressionHandler methodSecurityExpressionHandler(RoleHierarchy roleHierarchy) {
         DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();         DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
-        expressionHandler.setRoleHierarchy(roleHierarchy());+        expressionHandler.setRoleHierarchy(roleHierarchy);
         return expressionHandler;         return expressionHandler;
     }     }
 </sxh> </sxh>
  
-Les utilisateurs peuvent dans ce cas n'avoir qu'une seule authority, qui leur en confère plusieurs avec la hiérarchie des rôles. +Les utilisateurs peuvent dans ce cas n'avoir qu'une seule authority, qui leur en confère plusieurs grâce à la hiérarchie des rôles.
- +
-<WRAP alert> +
-Inutilisable pour l'instant avec la version Spring security 6.0.1 ([[https://github.com/s4-dut-info/R4.10-2023/issues/12|voir bug existant]]) +
-</WRAP>+
  
 +<wrap info>
 +Les méthodes **static** sont recommandées pour ces beans, afin qu'ils soient instanciés tôt dans le cycle de vie du contexte Spring.\\
 +La méthode **RoleHierarchyImpl.fromHierarchy(...)** est disponible à partir de Spring Security 6.3 ; pour les versions antérieures, utiliser **RoleHierarchyImpl.withDefaultRolePrefix()** ou **setHierarchy(...)**.
 +</wrap>
  
 ==== Configuration des rôles ==== ==== Configuration des rôles ====
  
-<sxh java;title:WebSecurityConfig>+<sxh java;title:SecurityConfig>
 @Configuration @Configuration
 @EnableWebSecurity @EnableWebSecurity
-@EnableMethodSecurity( +@EnableMethodSecurity 
-        prePostEnabled = true, proxyTargetClass = true +public class SecurityConfig {
-) +
-public class WebSecurityConfiguration {+
  
     @Bean     @Bean
-    public SecurityFilterChain configure(HttpSecurity http) throws Exception { +    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 
-        http.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests( +        http.authorizeHttpRequests(req -> req 
-                        (req) -> { +                .requestMatchers("/css/**", "/assets/**", "/login/**").permitAll()   // (1) 
-                            req.requestMatchers( +                .requestMatchers("/admin/**").hasRole("ADMIN")                       // (2) 
-                                            AntPathRequestMatcher.antMatcher("/css/**"), +                .requestMatchers("/user/**").hasAuthority("ROLE_USER")               // (3) 
-                                            AntPathRequestMatcher.antMatcher("/assets/**"), +                .requestMatchers("/staff/**").hasAnyAuthority("ROLE_USER", "ROLE_ADMIN", "ROLE_MANAGER") // (4) 
-                                            AntPathRequestMatcher.antMatcher("/login/**") +                .anyRequest().authenticated()                                        // (5) 
-                                    ) +        );
-                                    .permitAll(); +
-                            req.requestMatchers(AntPathRequestMatcher.antMatcher("/admin/**")).hasRole("ROLE_ADMIN"); // (2) +
-                            req.requestMatchers(AntPathRequestMatcher.antMatcher("/user/**")).hasAuthority("USER"); // (3) +
-                            req.requestMatchers(AntPathRequestMatcher.antMatcher("/staff/**")).hasAnyAuthority("USER", "ADMIN", "MANAGER"); // (4) +
-                            req.anyRequest().authenticated(); // (5) +
-                        } +
-                );+
         return http.build();         return http.build();
     }     }
Ligne 376: Ligne 375:
 ^Méthode ^ Description ^ ^Méthode ^ Description ^
 | 1 - **permitAll** | Pas de sécurisation sur les urls commençant par **/css**, **/assets**, **/login**. | | 1 - **permitAll** | Pas de sécurisation sur les urls commençant par **/css**, **/assets**, **/login**. |
-| 2 - **hasRole** | Les utilisateurs ayant le rôle **ROLE_ADMIN** peuvent accéder aux urls commençant par **/admin**. | +| 2 - **hasRole** | Les utilisateurs ayant le rôle **ADMIN** (authority **ROLE_ADMIN**) peuvent accéder aux urls commençant par **/admin**. | 
-| 3 - **hasAuthority** | Les utilisateurs ayant l'authority **USER** peuvent accéder aux urls commençant par **/user**. | +| 3 - **hasAuthority** | Les utilisateurs ayant l'authority **ROLE_USER** peuvent accéder aux urls commençant par **/user**. | 
-| 4 - **hasAnyAuthority** | Les utilisateurs ayant l'une des authorities **USER**, **ADMIN** ou **MANAGER** peuvent accéder aux urls commençant par **/staff**. |+| 4 - **hasAnyAuthority** | Les utilisateurs ayant l'une des authorities **ROLE_USER**, **ROLE_ADMIN** ou **ROLE_MANAGER** peuvent accéder aux urls commençant par **/staff**. |
 | 5 - **authenticated** | Pour toutes les autres URLs, il faut être authentifié. | | 5 - **authenticated** | Pour toutes les autres URLs, il faut être authentifié. |
  
-==== defense in depth ==== +<wrap important round> 
-Spring security permet de définir des authorisations sur les méthodes sollicitées, au delà des autorisations qu'il est possible de définir sur les URLs.+**Ordre des règles** : elles sont évaluées dans l'ordre de déclaration, la première qui correspond s'applique. Placez toujours les règles les plus spécifiques en premier, et **anyRequest()** en dernier. 
 +</wrap> 
 + 
 +==== Defense in depth ==== 
 +Spring security permet de définir des autorisations sur les méthodes sollicitées, au-delà des autorisations qu'il est possible de définir sur les URLs.
  
 === Activation === === Activation ===
  
-<sxh java;title:WebSecurityConfig;highlight:[3-7]>+<sxh java;title:SecurityConfig;highlight:[3-7]>
 @Configuration @Configuration
 @EnableWebSecurity @EnableWebSecurity
 @EnableMethodSecurity( @EnableMethodSecurity(
-    prePostEnabled = true,  +    prePostEnabled = true, 
-    securedEnabled = true, +    securedEnabled = true,
     jsr250Enabled = true     jsr250Enabled = true
 ) )
-public class WebSecurityConfiguration {+public class SecurityConfig {
     ...     ...
 } }
Ligne 400: Ligne 403:
  
 ^Propriété ^Défaut ^Description ^ ^Propriété ^Défaut ^Description ^
-|prePostEnabled | true | permet d’utiliser les annotations **@PreAuthorize** et **@PostAuthorize**. | +|prePostEnabled | true | permet d'utiliser les annotations **@PreAuthorize** et **@PostAuthorize**. | 
-|securedEnabled | false | permet d’utiliser l’annotation **@Secured**. | +|securedEnabled | false | permet d'utiliser l'annotation **@Secured**. | 
-|jsr250Enabled | false | permet d’utiliser l’annotation **@RolesAllowed**. | +|jsr250Enabled | false | permet d'utiliser l'annotation **@RolesAllowed**. |
  
 +<wrap info>
 +Dans les versions récentes de Spring Boot, **jakarta.annotation.security.RolesAllowed** remplace l'ancien package **javax**.
 +</wrap>
  
 == @Secured == == @Secured ==
Ligne 417: Ligne 422:
 == @RolesAllowed == == @RolesAllowed ==
 <sxh java> <sxh java>
-    @RolesAllowed(value = [ "ROLE_USER", "ROLE_MANAGER"])+    @RolesAllowed({"ROLE_USER", "ROLE_MANAGER"})
     public String userOrManager() {     public String userOrManager() {
         return "userOrManager";         return "userOrManager";
Ligne 430: Ligne 435:
  
 <sxh java> <sxh java>
-    @PreAuthorize("has_role('ROLE_VIEWER')")+    @PreAuthorize("hasRole('VIEWER')")
     public String getUsernameInUpperCase() {     public String getUsernameInUpperCase() {
-        return getUserName().upperCase();+        return getUserName().toUpperCase();
     }     }
 </sxh> </sxh>
- 
  
 Comparaison du paramètre **username** avec le nom de l'utilisateur connecté : Comparaison du paramètre **username** avec le nom de l'utilisateur connecté :
-<sxh kotlin>+ 
 +<sxh java>
     @PreAuthorize("#username == authentication.principal.username")     @PreAuthorize("#username == authentication.principal.username")
-    public List<String> getRoles(username:String) {+    public List<String> getRoles(String username) {
         ...         ...
     }     }
Ligne 451: Ligne 456:
   * En testant éventuellement le retour.   * En testant éventuellement le retour.
  
-<sxh kotlin> +<sxh java> 
-    @PostAuthorize("returnObject.username == authentication.principal.nickName")+    @PostAuthorize("returnObject.username == authentication.principal.username")
     public CustomUser loadUserDetail(String username) {     public CustomUser loadUserDetail(String username) {
         return userRoleRepository.loadUserByUserName(username);         return userRoleRepository.loadUserByUserName(username);
Ligne 458: Ligne 463:
 </sxh> </sxh>
  
-voir https://docs.spring.io/spring-security/reference/servlet/authorization/expression-based.html+Voir la [[https://docs.spring.io/spring-security/reference/servlet/authorization/method-security.html|documentation officielle sur la sécurité des méthodes]].
  
 ==== Mise en place CSRF ==== ==== Mise en place CSRF ====
Ligne 465: Ligne 470:
 === Activation === === Activation ===
  
-Activer CSRF dans le fichier **WebSecurityConfig** en enlevant la ligne :+La protection CSRF est **activée par défaut** dans Spring Security : il suffit de ne pas la désactiver.\\ 
 +Si votre configuration contient la ligne suivante, supprimez-la : 
 <sxh java;gutter:false> <sxh java;gutter:false>
 http.csrf(AbstractHttpConfigurer::disable) http.csrf(AbstractHttpConfigurer::disable)
 </sxh> </sxh>
  
-<wrap info> +Exception éventuelle pour la console H2 (uniquement en développement) :
-La protection csrf est activée par défaut dans **Spring security** +
-</wrap> +
- +
-Mettez éventuellement une exception pour la console H2 :+
  
 <sxh java;gutter:false> <sxh java;gutter:false>
-req.csrf(csrf->csrf.ignoringRequestMatchers(toH2Console()))+http.csrf(csrf -> csrf.ignoringRequestMatchers(PathRequest.toH2Console()))
 </sxh> </sxh>
  
 === Intégration dans les vues === === Intégration dans les vues ===
  
-Dans **application.properties**, exposer les attributs de requête dans les vues :+Dans **application.properties**, exposer les attributs de requête dans les vues (exemple pour Mustache) :
  
-<sxh ini;gutter:false> +<sxh ini;gutter:false;title:application.properties>
-# Expose Request Attributes+
 spring.mustache.servlet.expose-request-attributes=true spring.mustache.servlet.expose-request-attributes=true
 </sxh> </sxh>
Ligne 492: Ligne 494:
  
 <sxh html;gutter:false> <sxh html;gutter:false>
-<form> +<form method="post" action="..."> 
-...+    ...
     <input type="hidden"     <input type="hidden"
            name="{{_csrf.parameterName}}"            name="{{_csrf.parameterName}}"
            value="{{_csrf.token}}"/>            value="{{_csrf.token}}"/>
-...+    ...
 </form> </form>
 </sxh> </sxh>
  
 +<wrap info round>
 +Avec **Thymeleaf**, le token CSRF est inséré automatiquement dans les formulaires utilisant **th:action**.
 +</wrap>
  
-voir [[https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html|Spring Cross Site Request Forgery]] +<wrap important round> 
- +Attention à la route **/logout** : avec CSRF activé, elle doit être accédée uniquement via un **POST** incluant le token CSRF. 
- +</wrap>
  
 +Voir [[https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html|Spring Cross Site Request Forgery]]
  • web/framework/spring/security.1701770846.txt.gz
  • Dernière modification : il y a 3 ans
  • de jcheron