Introduction aux expressions de sécurité Spring

1. Introduction

Dans ce didacticiel, nous nous concentrerons sur les expressions de sécurité Spring, et bien sûr sur des exemples pratiques avec ces expressions.

Avant d'examiner des implémentations plus complexes (telles que ACL), il est important d'avoir une solide compréhension des expressions de sécurité - car elles peuvent être assez flexibles et puissantes si elles sont utilisées correctement.

Cet article est une extension des expressions de sécurité Spring - exemple hasRole.

2. Dépendances de Maven

Pour utiliser Spring Security, vous devez inclure la section suivante dans votre fichier pom.xml :

  org.springframework.security spring-security-web 5.2.3.RELEASE  

La dernière version peut être trouvée ici.

Et une note rapide - cette dépendance ne couvre que Spring Security; n'oubliez pas d'ajouter s pring-core et spring-context pour une application web complète.

3. Configuration

Jetons d'abord un coup d'œil à une configuration Java.

Nous allons étendre WebSecurityConfigurerAdapter - afin que nous ayons la possibilité de nous connecter à l'un des points d'extension proposés par la classe de base:

@Configuration @EnableAutoConfiguration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityJavaConfig extends WebSecurityConfigurerAdapter { ... }

Nous pouvons bien sûr également faire une configuration XML:

4. Expressions de sécurité Web

Maintenant, commençons à regarder les expressions de sécurité:

  • hasRole , hasAnyRole
  • hasAuthority , hasAnyAuthority
  • permitAll , denyAll
  • isAnonymous , isRememberMe , isAuthenticated , isFullyAuthenticated
  • principal , authentification
  • hasPermission

Et passons maintenant à chacun de ces éléments en détail.

4.1. hasRole, hasAnyRole

Ces expressions sont chargées de définir le contrôle d'accès ou l'autorisation à des URL ou des méthodes spécifiques dans votre application.

Regardons l'exemple:

@Override protected void configure(final HttpSecurity http) throws Exception { ... .antMatchers("/auth/admin/*").hasRole("ADMIN") .antMatchers("/auth/*").hasAnyRole("ADMIN","USER") ... } 

Dans cet exemple, nous spécifions l'accès à tous les liens commençant par / auth / restreint aux utilisateurs connectés avec le rôle USER ou le rôle ADMIN. De plus, pour accéder aux liens commençant par / auth / admin /, nous devons avoir le rôle ADMIN dans le système.

La même configuration peut être réalisée dans un fichier XML, en écrivant:

4.2. hasAuthority, hasAnyAuthority

Les rôles et les autorités sont similaires au printemps.

La principale différence est que les rôles ont une sémantique spéciale - à partir de Spring Security 4, le préfixe ' ROLE_ ' est automatiquement ajouté (s'il n'est pas déjà là) par toute méthode liée au rôle.

Ainsi, hasAuthority ('ROLE_ADMIN') est similaire à hasRole ('ADMIN') car le préfixe ' ROLE_ ' est ajouté automatiquement.

Mais l'avantage d'utiliser les autorités est que nous n'avons pas du tout besoin d'utiliser le préfixe ROLE_ .

Voici un exemple rapide où nous définissons des utilisateurs avec des droits spécifiques:

@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user1").password(encoder().encode("user1Pass")) .authorities("USER") .and().withUser("admin").password(encoder().encode("adminPass")) .authorities("ADMIN"); } 

On peut alors bien sûr utiliser ces expressions d'autorités:

@Override protected void configure(final HttpSecurity http) throws Exception { ... .antMatchers("/auth/admin/*").hasAuthority("ADMIN") .antMatchers("/auth/*").hasAnyAuthority("ADMIN", "USER") ... }

Comme nous pouvons le voir, nous ne mentionnons pas du tout les rôles ici. De plus, à partir du printemps 5, nous avons besoin d'un bean PasswordEncoder :

@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }

Enfin, nous pouvons bien sûr obtenir les mêmes fonctionnalités en utilisant la configuration XML:

Et:

4.3. permitAll, denyAll

Ces deux annotations sont également assez simples. Nous pouvons soit autoriser l'accès à certaines URL de notre service, soit refuser l'accès.

Jetons un coup d'œil à l'exemple:

... .antMatchers("/*").permitAll() ...

Avec cette configuration, nous autoriserons tous les utilisateurs (anonymes et connectés) à accéder à la page commençant par '/' (par exemple, notre page d'accueil).

Nous pouvons également refuser l'accès à l'ensemble de notre espace URL:

... .antMatchers("/*").denyAll() ...

Et encore une fois, la même configuration peut également être effectuée avec une configuration XML:

4.4. isAnonymous, isRememberMe, isAuthenticated, isFullyAuthenticated

In this subsection we focus on expressions related to login status of the user. Let's start with user that didn't log in to our page. By specifying following in Java config, we enable all unauthorized users to access our main page:

... .antMatchers("/*").anonymous() ...

The same in XML config:

If we want to secure the website that everybody who uses it will be required to login, we need to use isAuthenticated() method:

... .antMatchers("/*").authenticated() ...

or XML version:

Moreover, we have two additional expressions, isRememberMe() and isFullyAuthenticated(). Through the use of cookies, Spring enables remember-me capabilities so there is no need to log into the system each time. You can read more about Remember Me here.

In order to give the access to users that were logged in only by remember me function, we may use this:

... .antMatchers("/*").rememberMe() ...

or XML version:

Finally, some parts of our services require the user to be authenticated again even if the user is already logged in. For example, user wants to change settings or payment information; it's of course good practice to ask for manual authentication in the more sensitive areas of the system.

In order to do that, we may specify isFullyAuthenticated(), which returns true if the user is not an anonymous or a remember-me user:

... .antMatchers("/*").fullyAuthenticated() ...

or the XML version:

4.5. principal, authentication

These expressions allow accessing the principal object representing the current authorized (or anonymous) user and the current Authentication object from the SecurityContext, respectively.

We can, for example, use principal to load a user's email, avatar, or any other data that is accessible in the logged in user.

And authentication provides information about the full Authentication object, along with its granted authorities.

Both are described in further detail in the following article: Retrieve User Information in Spring Security.

4.6. hasPermission APIs

This expression is documented and intended to bridge between the expression system and Spring Security’s ACL system, allowing us to specify authorization constraints on individual domain objects, based on abstract permissions.

Let's have a look at an example. We have a service that allows cooperative writing articles, with a main editor, deciding which article proposed by other authors should be published.

In order to allow usage of such a service, we may create following methods with access control methods:

@PreAuthorize("hasPermission(#articleId, 'isEditor')") public void acceptArticle(Article article) { … }

Only authorized user can call this method, and also user needs to have permission isEditor in the service.

We also need to remember to explicitly configure a PermissionEvaluator in our application context:

customInterfaceImplementation sera la classe qui implémente PermissionEvaluator.

Bien sûr, nous pouvons également le faire avec la configuration Java:

@Override protected MethodSecurityExpressionHandler expressionHandler() { DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler(); expressionHandler.setPermissionEvaluator(new CustomInterfaceImplementation()); return expressionHandler; }

5. Conclusion

Ce didacticiel est une introduction et un guide complets aux expressions de sécurité Spring.

Tous les exemples discutés ici sont disponibles sur le projet GitHub.