Custom Implementation Example
Deze gids doorloopt het bouwen van een complete aangepaste beveiligingsimplementatie met behulp van sessie-gebaseerde authenticatie. Je leert hoe de vier kerninterfaces samenwerken door ze vanaf nul te implementeren.
De Spring Security-integratie configureert automatisch alles wat hier wordt weergegeven. Bouw alleen aangepaste beveiliging als je specifieke vereisten hebt of geen gebruik maakt van Spring Boot.
Wat je gaat bouwen
Een werkend beveiligingssysteem met vier klassen:
- SecurityConfiguration - Definieert het beveiligingsgedrag en de omleidingslocaties
- SecurityContext - Houdt bij wie is ingelogd met behulp van HTTP-sessies
- SecurityManager - Coördineert beveiligingscontroles en biedt inloggen/afmelden aan
- SecurityRegistrar - Verbindt alles met elkaar bij app-startup
Dit voorbeeld maakt gebruik van sessie-gebaseerde opslag, maar je zou dezelfde interfaces kunnen implementeren met behulp van database-query's, LDAP of een andere authenticatie-backend.
Hoe de onderdelen samenwerken
Stroom:
SecurityRegistrardraait bij opstarten, maakt de manager, registreert evaluators en koppelt de observerSecurityManagercoördineert alles - het biedt de context en configuratie aan evaluatorsSecurityContextbeantwoordt "Wie is ingelogd?" door te lezen uit HTTP-sessiesSecurityConfigurationbeantwoordt "Waarheen omleiden?" voor inlog- en toegang geweigerd pagina'sEvaluatorsnemen toegangsbeslissingen met behulp van de context en configuratie
Stap 1: Definieer beveiligingsconfiguratie
De configuratie vertelt het beveiligingssysteem hoe het zich moet gedragen en waar het gebruikers naartoe moet omleiden:
package com.securityplain.security;
import com.webforj.router.history.Location;
import com.webforj.router.security.RouteSecurityConfiguration;
import java.util.Optional;
/**
* Beveiligingsconfiguratie voor de applicatie.
*
* <p>
* Definieert waar gebruikers naartoe moeten worden omgeleid wanneer authenticatie vereist is of toegang wordt geweigerd.
* </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- Beveiliging is actiefisSecureByDefault() = false- Routes zijn openbaar tenzij geannoteerd (gebruiktrueom authenticatie op alle routes standaard te vereisen)/login- Waar niet-geauthenticeerde gebruikers naartoe gaan/access-denied- Waar geauthenticeerde gebruikers zonder machtigingen naartoe gaan
Stap 2: Implementeer beveiligingscontext
De context houdt bij wie is ingelogd. Deze implementatie gebruikt HTTP-sessies om gebruikersinformatie op te slaan:
Hoe het werkt:
isAuthenticated()controleert of er een gebruikersprincipal in de sessie bestaatgetPrincipal()haalt de gebruikersnaam uit de sessieopslaghasRole()controleert of de rolset van de gebruiker de opgegeven rol bevatgetAttribute()/setAttribute()beheren aangepaste beveiligingsattributenEnvironment.getSessionAccessor()biedt thread-veilige sessie-toegang
Stap 3: Maak beveiligingsmanager aan
De manager coördineert beveiligingsbeslissingen. Het breidt AbstractRouteSecurityManager uit, dat evaluator ketens en toegang weigeringen afhandelt:
Hoe het werkt:
- Breidt
AbstractRouteSecurityManageruit om de evaluatorketenlogica over te nemen - Biedt implementaties van
getConfiguration()engetSecurityContext() - Voegt
login()toe om gebruikers te authenticeren en referenties in de sessie op te slaan - Voegt
logout()toe om de sessie te wissen en door te verwijzen naar de inlogpagina - Gebruik
SessionObjectTablevoor eenvoudige sessieopslag - Slaat zichzelf op in
ObjectTablevoor toegang door de hele app
Stap 4: Verbind alles bij opstarten
De registrar verbindt alle onderdelen wanneer de app opstart:
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;
/**
* Registreert routebeveiligingscomponenten tijdens de opstart van de applicatie.
*
* <p>
* Stelt beveiligingsmanager en evaluators in met de router.
* </p>
*/
@AppListenerPriority(1)
public class SecurityRegistrar implements AppLifecycleListener {
/**
* {@inheritDoc}
*/
@Override
public void onWillRun(App app) {
// Maak beveiligingsmanager aan
SecurityManager securityManager = new SecurityManager();
securityManager.saveCurrent(securityManager);
// Registreer ingebouwde evaluators met prioriteiten
securityManager.registerEvaluator(new DenyAllEvaluator(), 0);
securityManager.registerEvaluator(new AnonymousAccessEvaluator(), 1);
securityManager.registerEvaluator(new PermitAllEvaluator(), 2);
securityManager.registerEvaluator(new RolesAllowedEvaluator(), 3);
// Maak beveiligingsobserver en koppel aan router
RouteSecurityObserver securityObserver = new RouteSecurityObserver(securityManager);
Router router = Router.getCurrent();
if (router != null) {
router.getRenderer().addObserver(securityObserver);
}
}
}
Registreer de listener:
Maak src/main/resources/META-INF/services/com.webforj.AppLifecycleListener aan met:
com.securityplain.security.SecurityRegistrar
Dit registreert je AppLifecycleListener zodat deze draait bij de opstart van de app.
Hoe het werkt:
- Draait vroeg (
@AppListenerPriority(1)) om beveiliging in te stellen voordat routes laden - Creëert de beveiligingsmanager en slaat deze globaal op
- Registreert ingebouwde evaluators in prioriteitsvolgorde (lagere nummers draaien als eerste)
- Creëert de observer die navigatie onderschept
- Koppelt de observer aan de router zodat beveiligingscontroles automatisch plaatsvinden
Nadat dit draait, is de beveiliging actief voor alle navigatie.
Gebruik je implementatie
Maak een inlogweergave aan
De volgende weergave maakt gebruik van de Login component.
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("Inloggen")
@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());
}
}