Contactez-nous

Configuration des règles d'accès via `HttpSecurity` (antMatchers, mvcMatchers)

Maîtrisez la configuration des autorisations dans Spring Security avec HttpSecurity, en utilisant antMatchers et mvcMatchers pour définir des règles d'accès précises à vos ressources web.

Introduction à la configuration des autorisations avec HttpSecurity

Au coeur de la gestion des autorisations dans Spring Security se trouve l'objet HttpSecurity. C'est lui qui permet de définir de manière fluide et expressive quelles requêtes sont autorisées, pour qui, et dans quelles conditions. La configuration se fait généralement au sein d'une classe annotée @Configuration, en définissant un bean de type SecurityFilterChain.

Le point d'entrée principal pour définir les règles d'accès aux URL est la méthode authorizeHttpRequests() (ou son prédécesseur authorizeRequests() qui est maintenant déprécié). Cette méthode retourne un configurateur sur lequel on peut chaîner des appels pour spécifier des 'matchers' (des sélecteurs de requêtes) et les règles d'autorisation associées.

L'idée fondamentale est de décrire des chemins d'URL ou des points d'entrée spécifiques de votre application et d'y associer des exigences de sécurité. Par exemple, certaines URL peuvent être publiques, d'autres nécessitent une simple authentification, tandis que certaines requièrent des rôles ou des permissions spécifiques. Spring Security évalue ces règles dans l'ordre où elles sont déclarées.

Utiliser antMatchers pour définir les règles basées sur les chemins d'URL

La méthode la plus classique et largement utilisée pour spécifier les chemins d'URL est antMatchers(). Elle utilise la syntaxe Ant-style pour le pattern matching, ce qui offre une grande flexibilité pour cibler des URL spécifiques ou des groupes d'URL.

Voici les principaux caractères spéciaux utilisés dans les patterns Ant :

  • ? : correspond à un seul caractère.
  • * : correspond à zéro ou plusieurs caractères dans un seul segment de chemin (entre les '/').
  • ** : correspond à zéro ou plusieurs segments de chemin.

On peut également spécifier la méthode HTTP à laquelle la règle s'applique en passant un objet HttpMethod en premier argument de antMatchers().

Après avoir spécifié le(s) matcher(s), on enchaîne avec la règle d'autorisation :

  • permitAll() : Autorise toutes les requêtes (authentifiées ou non).
  • denyAll() : Refuse toutes les requêtes.
  • authenticated() : Autorise uniquement les utilisateurs authentifiés.
  • hasRole('ROLE_NOM') ou hasAnyRole('ROLE_UN', 'ROLE_DEUX') : Autorise les utilisateurs ayant le(s) rôle(s) spécifié(s) (notez le préfixe 'ROLE_' implicitement ajouté si absent).
  • hasAuthority('PERMISSION') ou hasAnyAuthority('PERM_A', 'PERM_B') : Autorise les utilisateurs ayant la/les permission(s) spécifiée(s).
  • access(String expressionSpEL) : Permet d'utiliser des expressions SpEL (Spring Expression Language) pour des règles plus complexes.

Voici un exemple de configuration utilisant antMatchers :

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .antMatchers(HttpMethod.GET, "/api/public/**", "/css/**", "/js/**").permitAll() // Public GET requests
                .antMatchers("/api/admin/**").hasRole("ADMIN") // Requires ADMIN role
                .antMatchers("/api/users/me").authenticated() // Requires authentication
                .anyRequest().authenticated() // All other requests need authentication
            )
            .formLogin(Customizer.withDefaults()) // Example: enable form login
            .httpBasic(Customizer.withDefaults()); // Example: enable HTTP Basic
        return http.build();
    }

    // ... other beans like UserDetailsService, PasswordEncoder
}

Important : Les règles sont évaluées dans l'ordre. La première règle qui correspond à la requête est appliquée. Il est donc crucial de placer les règles les plus spécifiques avant les plus générales (par exemple, /api/admin/** avant /api/** ou anyRequest()).

mvcMatchers : l'alternative intégrée à Spring MVC

Une alternative intéressante à antMatchers est mvcMatchers(). Au lieu de se baser uniquement sur les patterns d'URL textuels, mvcMatchers s'intègre plus profondément avec Spring MVC. Il utilise l'introspection des mappings de contrôleurs (les annotations @RequestMapping, @GetMapping, etc.) pour déterminer les chemins.

Le principal avantage de mvcMatchers est sa robustesse face aux changements. Si vous refactorisez une URL dans votre contrôleur, la règle définie avec mvcMatchers s'adaptera automatiquement, alors qu'une règle antMatchers nécessiterait une mise à jour manuelle du pattern textuel. Cela réduit le risque d'erreurs et de failles de sécurité dues à des configurations désynchronisées.

La syntaxe est similaire à celle de antMatchers, mais on spécifie généralement le chemin tel qu'il apparaîtrait dans l'annotation de mapping, sans avoir besoin de se soucier autant des wildcards complexes dans certains cas. On peut également spécifier la méthode HTTP.

Exemple d'utilisation de mvcMatchers :

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .mvcMatchers(HttpMethod.GET, "/public-content").permitAll()
                .mvcMatchers("/admin/dashboard").hasRole("ADMIN")
                .mvcMatchers("/profile/{userId}").access("@webSecurity.checkUserId(authentication, #userId)") // Example with SpEL
                .anyRequest().authenticated()
            )
            // ... other configurations
            ;
        return http.build();
    }

    // ...
}

Dans cet exemple, /profile/{userId} utilise mvcMatchers pour correspondre au mapping du contrôleur et permet même d'accéder à la variable de chemin userId via SpEL pour des vérifications d'autorisation plus fines.

Le choix entre antMatchers et mvcMatchers dépend du contexte. antMatchers est plus général et fonctionne même sans Spring MVC (par exemple, avec WebFlux ou des ressources statiques non mappées explicitement), tandis que mvcMatchers offre une meilleure intégration et robustesse dans un contexte Spring MVC classique.

Bonnes pratiques et ordre des règles

La configuration de la sécurité via HttpSecurity demande une certaine rigueur pour éviter les erreurs ou les failles. La règle d'or est l'ordre des déclarations. Spring Security applique la première règle correspondante. Par conséquent, vous devez toujours déclarer les règles les plus spécifiques en premier, suivies des règles plus générales.

Par exemple, si vous avez antMatchers("/api/**").authenticated() et antMatchers("/api/public").permitAll(), la règle pour /api/public doit impérativement être déclarée avant celle pour /api/**. Sinon, la règle plus générale interceptera toutes les requêtes sous /api/, y compris /api/public, et exigera une authentification.

Il est recommandé de regrouper logiquement les règles. Par exemple, commencez par définir toutes les ressources publiques (CSS, JS, pages d'accueil, API publiques), puis les ressources nécessitant une authentification simple, et enfin les ressources nécessitant des rôles ou autorisations spécifiques. Terminez toujours par une règle de repli générale, comme anyRequest().authenticated() ou anyRequest().denyAll(), pour vous assurer qu'aucune URL n'est laissée sans protection par inadvertance.

Enfin, privilégiez la lisibilité. Utilisez des sauts de ligne et une indentation claire dans votre configuration Java. N'hésitez pas à extraire des logiques complexes dans des méthodes ou des beans dédiés, notamment lorsque vous utilisez des expressions SpEL complexes avec la méthode access(). Une configuration de sécurité claire est plus facile à maintenir et à auditer.