III. Application avec Spring Security
1. Authentification par JWT
Après avoir discuté des éléments internes du framework Spring Security, configurons-le pour l'authentification "STATELESS" (sans état) avec un jeton JWT .
Pour personnaliser Spring Security pour l'utilisation de JWT, nous avons besoin d'une classe de configuration annotée avec @EnableWebSecurity . De plus, pour simplifier le processus de personnalisation, le framework expose une classe appelée WebSecurityConfigurerAdapter .On étend cette classe et on surcharge ses deux méthodes de manière à :
1) Configurer le gestionnaire d'authentification avec le bon fournisseur
2) Configurer la sécurité Web (URL publiques, URL privées, autorisation, etc.) ; voir ci-dessous
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // TODO configure authentication manager } @Override protected void configure(HttpSecurity http) throws Exception { // TODO configure web security } }
Dans une application classique , nous stockons les identités des utilisateurs dans une base de données. Ces identités sont mappées par l'entité User et leurs opérations CRUD sont définies par un référentiel UserRepo Spring Data.
Désormais, lorsque nous acceptons la demande d'authentification, nous devons récupérer l'identité correcte de la base de données à l'aide des informations d'identification fournies, puis la vérifier. Pour cela, nous avons besoin de l'implémentation de l'interface UserDetailsService, qui est définie comme suit :
public interface UserDetailsService { UserDetails loadUserByUsername (String username) throws UsernameNotFoundException ; }
Ici, nous pouvons voir qu'il est nécessaire de renvoyer l'objet qui implémente l'interface UserDetails, et notre entité User l'implémente (pour les détails d'implémentation.
Étant donné qu'il n'expose que le prototype à fonction unique, nous pouvons le traiter comme une interface fonctionnelle et fournir une implémentation sous la forme d'une expression lambda. Ici, l'appel de fonction auth.userDetailsService lancera l'instance DaoAuthenticationProvider à l'aide de notre implémentation de l'interface UserDetailsService et l'enregistrera dans le gestionnaire d'authentification. Avec le fournisseur d'authentification, nous devons configurer un gestionnaire d'authentification avec le schéma de codage de mot de passe correct qui sera utilisé pour la vérification des informations d'identification. Pour cela, nous devons exposer l'implémentation préférée de l'interface PasswordEncoder sous forme de bean. Dans notre exemple de projet, nous utiliserons l’algorithme de hachage de mot de passe bcrypt.
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasRole("USER") .anyRequest().authenticated() .and() .formLogin() .and() .logout() .and() .csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder); } }
Dans le code ci-dessus, Spring Security est activé à l'aide de l'annotation @EnableWebSecurity. La méthode configure(HttpSecurity http) est utilisée pour configurer le contrôle d'accès, en spécifiant quelles URL nécessitent quels rôles accéder et que toute demande nécessite une authentification. La méthode formLogin() active l'authentification basée sur un formulaire, la méthode logout() active la prise en charge de la déconnexion et la méthode csrf().disable() désactive la protection CSRF. La méthode configure(AuthenticationManagerBuilder auth) est utilisée pour configurer l'authentification, en spécifiant quelle implémentation UserDetailsService utiliser pour obtenir les informations utilisateur et les mots de passe, et quelle implémentation PasswordEncoder utiliser pour la vérification du mot de passe.
...