Getting Started
Spring Security fournit une authentification et une autorisation pour les applications Spring Boot. Lorsqu'il est intégré avec webforJ, il protège les routes à l'aide d'annotations pendant que Spring gère la gestion des utilisateurs et des sessions.
Ce guide couvre l'ajout de Spring Security à votre application webforJ, la configuration de l'authentification, la création de vues de connexion et la protection des routes avec un contrôle d'accès basé sur les rôles.
Pour une compréhension complète des fonctionnalités et des concepts de Spring Security, consultez la documentation de Spring Security.
Ajouter la dépendance Spring Security
Ajoutez le starter Spring Security à votre pom.xml :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Cette seule dépendance apporte le cadre d'authentification de Spring Security, des encodeurs de mot de passe et une gestion des sessions. La version est automatiquement gérée par votre POM parent Spring Boot.
Configurer Spring security
Créez une classe de configuration de sécurité qui connecte Spring Security avec webforJ. Cette classe définit comment les utilisateurs sont authentifiés et quelles pages gèrent la connexion et le refus d'accès :
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.with(WebforjSecurityConfigurer.webforj(), configurer -> configurer
.loginPage(LoginView.class)
.accessDeniedPage(AccessDenyView.class)
.logout())
.build();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("admin"))
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
AuthenticationManager authenticationManager(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(authenticationProvider);
}
}
Cette configuration crée quatre beans Spring qui fonctionnent ensemble :
SecurityFilterChain connecte Spring Security avec le système de routage de webforJ. La méthode WebforjSecurityConfigurer.webforj() intègre l'authentification de Spring Security avec le routage webforJ. Vous spécifiez quelles classes de composants gèrent la connexion et le refus d'accès, et Spring appliquera l'authentification avant de rendre les routes protégées.
-
La méthode
loginPage()indique à Spring Security où les utilisateurs doivent s'authentifier. Passez votre classe de composant de vue de connexion, et webforJ résoudra automatiquement le chemin de la route à partir de l'annotation@Route. Lorsque des utilisateurs non authentifiés essaient d'accéder à des routes protégées, ils sont redirigés ici. -
La méthode
accessDeniedPage()définit où les utilisateurs authentifiés se rendent lorsqu'ils manquent de permissions pour une route. Par exemple, un utilisateur essayant d'accéder à une route réservée aux admins est redirigé vers cette page. -
La méthode
logout()active le point de terminaison de déconnexion à/logout. Après s'être déconnectés, les utilisateurs sont redirigés vers la page de connexion avec un paramètre?logout.
PasswordEncoder utilise BCrypt pour hacher les mots de passe de manière sécurisée. Spring Security applique automatiquement cet encodeur lors de la connexion pour comparer le mot de passe soumis avec le hachage stocké.
UserDetailsService indique à Spring Security où trouver les informations utilisateur lors de l'authentification. Cet exemple utilise un stockage en mémoire avec deux utilisateurs : user/password et admin/admin.
AuthenticationManager coordonne le processus d'authentification. Il utilise un fournisseur qui charge des utilisateurs à partir de UserDetailsService et vérifie les mots de passe avec le PasswordEncoder.
Créer la vue de connexion
Créez une vue qui présente une boîte de dialogue de connexion et soumet les identifiants à Spring Security. La vue suivante utilise le composant Login :
@Route("/signin")
@AnonymousAccess
public class LoginView extends Composite<Login> implements DidEnterObserver {
private final Login self = getBoundComponent();
public LoginView() {
self.setAction("/signin");
whenAttached().thenAccept(c -> self.open());
}
@Override
public void onDidEnter(DidEnterEvent event, ParametersBag params) {
ParametersBag queryParams = event.getLocation().getQueryParameters();
if (queryParams.containsKey("error")) {
Toast.show("Nom d'utilisateur ou mot de passe invalide. Veuillez réessayer.", Theme.DANGER);
}
if (queryParams.containsKey("logout")) {
Toast.show("Vous avez été déconnecté avec succès.", Theme.GRAY);
}
}
}
L'annotation @AnonymousAccess marque cette route comme publique afin que les utilisateurs non authentifiés puissent accéder à la page de connexion. Sans cette annotation, les utilisateurs seraient redirigés loin de la page de connexion, créant ainsi une boucle infinie.
La ligne setAction("/signin") est cruciale, elle configure le composant Login pour POST des identifiants vers le point de terminaison d'authentification de Spring. Spring intercepte cette soumission, vérifie les identifiants et accorde l'accès ou redirige vers la page avec un paramètre d'erreur.
L'observateur onDidEnter vérifie les paramètres de requête que Spring ajoute pour communiquer les résultats. Lorsque l'authentification échoue, Spring redirige vers /signin?error. Après une déconnexion, il redirige vers /signin?logout. L'observateur affiche des messages appropriés en fonction de ces paramètres.
Le chemin dans setAction("/signin") doit correspondre à votre chemin @Route("/signin"). Spring intercepte les soumissions de formulaires vers ce chemin exact pour l'authentification. Si vous avez besoin de chemins différents pour la page de connexion et le traitement de l'authentification, configurez-les séparément dans SecurityConfig :
.loginPage("/signin", "/authenticate")
Cela affiche la page de connexion à /signin mais traite l'authentification à /authenticate.
Créer la vue de refus d'accès
Créez une vue qui s'affiche lorsque les utilisateurs n'ont pas l'autorisation d'accéder à une route :
@Route(value = "/access-denied", outlet = MainLayout.class)
public class AccessDenyView extends Composite<Div> {
private final Div self = getBoundComponent();
public AccessDenyView() {
Paragraph message = new Paragraph("Oups ! Cette zone est réservée aux VIP.");
Paragraph subMessage = new Paragraph(
"On dirait que vous avez essayé de vous introduire dans le salon exécutif ! Soit vous obtenez de meilleurs identifiants, soit vous retournez dans les zones publiques où le café est gratuit de toute façon.");
self.add(message, subMessage);
}
}
Cette vue est rendue lorsque des utilisateurs authentifiés tentent d'accéder à des routes pour lesquelles ils n'ont pas la permission, comme un utilisateur essayant d'accéder à une route réservée aux admins.