Custom Implementation Example
Ce guide vous accompagne dans la construction d'une implémentation de sécurité personnalisée complète utilisant l'authentification basée sur les sessions. Vous apprendrez comment les quatre interfaces principales fonctionnent ensemble en les mettant en œuvre à partir de zéro.
L'intégration Spring Security configure automatiquement tout ce qui est montré ici. Ne créez une sécurité personnalisée que si vous avez des exigences spécifiques ou si vous n'utilisez pas Spring Boot.
Ce que vous allez construire
Un système de sécurité fonctionnel avec quatre classes :
- SecurityConfiguration - Définit le comportement de sécurité et les emplacements de redirection
- SecurityContext - Suit qui est connecté en utilisant des sessions HTTP
- SecurityManager - Coordonne les vérifications de sécurité et fournit les fonctionnalités de connexion/déconnexion
- SecurityRegistrar - Connecte tout ensemble au démarrage de l'application
Cet exemple utilise le stockage basé sur les sessions, mais vous pourriez mettre en œuvre les mêmes interfaces en utilisant des requêtes de base de données, LDAP ou tout autre backend d'authentification.
Comment les éléments fonctionnent ensemble
Flux :
SecurityRegistrars'exécute au démarrage, crée le manager, enregistre les évaluateurs et attache l'observateurSecurityManagercoordonne tout - il fournit le contexte et la configuration aux évaluateursSecurityContextrépond à la question "Qui est connecté ?" en lisant les sessions HTTPSecurityConfigurationrépond à la question "Où rediriger ?" pour les pages de connexion et d'accès refuséEvaluatorsprennent des décisions d'accès en utilisant le contexte et la configuration
Étape 1 : Définir la configuration de sécurité
La configuration indique au système de sécurité comment se comporter et où rediriger les utilisateurs :
package com.securityplain.security;
import com.webforj.router.history.Location;
import com.webforj.router.security.RouteSecurityConfiguration;
import java.util.Optional;
/**
* Configuration de sécurité pour l'application.
*
* <p>
* Définit où rediriger les utilisateurs lorsque l'authentification est requise ou l'accès est refusé.
* </p>
*/
public class SecurityConfiguration implements RouteSecurityConfiguration {
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean isSecureByDefault() {
return false;
}
@Override
public Optional<Location> getAuthenticationLocation() {
return Optional.of(new Location("/login"));
}
@Override
public Optional<Location> getDenyLocation() {
return Optional.of(new Location("/access-denied"));
}
}
isEnabled() = true- La sécurité est activeisSecureByDefault() = false- Les routes sont publiques sauf annotation (utiliseztruepour exiger l'authentification sur toutes les routes par défaut)/login- Où vont les utilisateurs non authentifiés/access-denied- Où vont les utilisateurs authentifiés sans autorisations
Étape 2 : Implémenter le contexte de sécurité
Le contexte suit qui est connecté. Cette implémentation utilise des sessions HTTP pour stocker les informations de l'utilisateur :
Comment cela fonctionne :
isAuthenticated()vérifie si un principal utilisateur existe dans la sessiongetPrincipal()récupère le nom d'utilisateur du stockage de sessionhasRole()vérifie si l'ensemble des rôles de l'utilisateur contient le rôle spécifiégetAttribute()/setAttribute()gèrent les attributs de sécurité personnalisésEnvironment.getSessionAccessor()fournit un accès aux sessions sûr pour les threads
Étape 3 : Créer le gestionnaire de sécurité
Le gestionnaire coordonne les décisions de sécurité. Il étend AbstractRouteSecurityManager, qui gère les chaînes d'évaluateurs et le refus d'accès :
Comment cela fonctionne :
- Étend
AbstractRouteSecurityManagerpour hériter de la logique de chaîne d'évaluateurs - Fournit les implémentations de
getConfiguration()etgetSecurityContext() - Ajoute
login()pour authentifier les utilisateurs et stocker les informations d'identification dans la session - Ajoute
logout()pour effacer la session et rediriger vers la page de connexion - Utilise
SessionObjectTablepour un stockage simple des sessions - Se stocke dans
ObjectTablepour un accès à l'échelle de l'application
Étape 4 : Connecter tout au démarrage
Le registraire connecte tous les éléments lorsque l'application démarre :
package com.securityplain.security;
import com.webforj.App;
import com.webforj.AppLifecycleListener;
import com.webforj.annotation.AppListenerPriority;
import com.webforj.router.Router;
import com.webforj.router.security.RouteSecurityObserver;
import com.webforj.router.security.evaluator.AnonymousAccessEvaluator;
import com.webforj.router.security.evaluator.DenyAllEvaluator;
import com.webforj.router.security.evaluator.PermitAllEvaluator;
import com.webforj.router.security.evaluator.RolesAllowedEvaluator;
/**
* Enregistre les composants de sécurité des routes pendant le démarrage de l'application.
*
* <p>
* Configure le gestionnaire de sécurité et les évaluateurs avec le routeur.
* </p>
*/
@AppListenerPriority(1)
public class SecurityRegistrar implements AppLifecycleListener {
/**
* {@inheritDoc}
*/
@Override
public void onWillRun(App app) {
// Créer le gestionnaire de sécurité
SecurityManager securityManager = new SecurityManager();
securityManager.saveCurrent(securityManager);
// Enregistrer les évaluateurs intégrés avec des priorités
securityManager.registerEvaluator(new DenyAllEvaluator(), 0);
securityManager.registerEvaluator(new AnonymousAccessEvaluator(), 1);
securityManager.registerEvaluator(new PermitAllEvaluator(), 2);
securityManager.registerEvaluator(new RolesAllowedEvaluator(), 3);
// Créer l'observateur de sécurité et l'attacher au routeur
RouteSecurityObserver securityObserver = new RouteSecurityObserver(securityManager);
Router router = Router.getCurrent();
if (router != null) {
router.getRenderer().addObserver(securityObserver);
}
}
}
Enregistrer l'écouteur :
Créez src/main/resources/META-INF/services/com.webforj.AppLifecycleListener avec :
com.securityplain.security.SecurityRegistrar
Cela enregistre votre AppLifecycleListener pour qu'il s'exécute au démarrage de l'application.
Comment cela fonctionne :
- S'exécute tôt (
@AppListenerPriority(1)) pour configurer la sécurité avant le chargement des routes - Crée le gestionnaire de sécurité et le stocke globalement
- Enregistre les évaluateurs intégrés par ordre de priorité (les nombres plus bas s'exécutent en premier)
- Crée l'observateur qui intercepte la navigation
- Attache l'observateur au routeur afin que les vérifications de sécurité se produisent automatiquement
Après cela, la sécurité est active pour toute navigation.
Utiliser votre implémentation
Créer une vue de connexion
La vue suivante utilise le composant Login.
package com.securityplain.views;
import com.securityplain.security.SecurityManager;
import com.webforj.component.Composite;
import com.webforj.component.login.Login;
import com.webforj.router.Router;
import com.webforj.router.annotation.FrameTitle;
import com.webforj.router.annotation.Route;
import com.webforj.router.history.Location;
import com.webforj.router.security.annotation.AnonymousAccess;
@Route("/login")
@FrameTitle("Connexion")
@AnonymousAccess
public class LoginView extends Composite<Login> {
private final Login self = getBoundComponent();
public LoginView() {
self.onSubmit(e -> {
var result = SecurityManager.getCurrent().login(
e.getUsername(), e.getPassword()
);
if (result.isGranted()) {
Router.getCurrent().navigate(new Location("/"));
} else {
self.setError(true);
self.setEnabled(true);
}
});
self.whenAttached().thenAccept(c -> self.open());
}
}