Siirry pääsisältöön

Custom Implementation Example

Avaa ChatGPT:ssä

Tämä opas käy läpi rakentamisen täydellisen mukautetun turvallisuusratkaisun käyttäen istuntoon perustuvaa todennusta. Opit, miten neljä ydintoimintoliittymää toimii yhdessä toteuttamalla ne alusta alkaen.

Useimmat sovellukset pitäisi käyttää Spring Securityä

Spring Security -integraatio konfiguroi automaattisesti kaiken, mitä täällä on esitetty. Rakenna vain mukautettu turvallisuus, jos sinulla on erityisiä vaatimuksia tai et käytä Spring Bootia.

Mitä rakennat

Toimiva turvallisuusjärjestelmä, jossa on neljä luokkaa:

  • SecurityConfiguration - Määrittelee turvallisuuskäyttäytymisen ja uudelleenohjauspaikat
  • SecurityContext - Seuraa, kuka on kirjautuneena sisään käyttäen HTTP-istuntoja
  • SecurityManager - Koordinoi turvallisuustarkistuksia ja tarjoaa kirjautumis-/uloskirjautumismahdollisuuden
  • SecurityRegistrar - Yhdistää kaiken sovelluksen käynnistämisen yhteydessä

Esimerkki käyttää istuntoon perustuvaa tallennusta, mutta voit toteuttaa samat toimintoliittymät käyttäen tietokantakyselyitä, LDAP:ta tai mitä tahansa muuta todennusbackendiä.

Miten osat toimivat yhdessä

Prosessi:

  1. SecurityRegistrar suorittaa käynnistyksen yhteydessä, luo hallitsijan, rekisteröi arvioijat ja liittää tarkkailijan
  2. SecurityManager koordinoi kaiken - se tarjoaa kontekstin ja konfiguraation arvioijille
  3. SecurityContext vastaa kysymykseen "Kuka on kirjautuneena?" lukemalla HTTP-istunnoista
  4. SecurityConfiguration vastaa kysymykseen "Mihin ohjata?" kirjautumis- ja pääsykielto -sivuille
  5. Evaluators tekevät pääsypäätöksiä käyttäen kontekstia ja konfiguraatiota

Vaihe 1: Määritä turvallisuuskonfiguraatio

Konfigurointi kertoo turvallisuusjärjestelmälle, miten käyttäytyä ja minne ohjata käyttäjiä:

SecurityConfiguration.java
package com.securityplain.security;

import com.webforj.router.history.Location;
import com.webforj.router.security.RouteSecurityConfiguration;
import java.util.Optional;

/**
* Turvallisuuskonfiguraatio sovellukselle.
*
* <p>
* Määrittelee minne ohjata käyttäjiä, kun todennus on vaadittu tai pääsy on kielletty.
* </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 - Turvallisuus on aktiivinen
  • isSecureByDefault() = false - Reitit ovat julkisia, ellei toisin ole merkattu (käytä true vaatiaksesi todennusta kaikilla reiteillä oletuksena)
  • /login - Minne todennusta vailla olevat käyttäjät menevät
  • /access-denied - Minne todennetut käyttäjät, joilla ei ole oikeuksia, menevät

Vaihe 2: Toteuta turvallisuuskonteksti

Konteksti seuraa, kuka on kirjautuneena. Tämä toteutus käyttää HTTP-istuntoja käyttäjätietojen tallentamiseen:

SecurityContext.java
package com.securityplain.security;

import com.webforj.Environment;
import com.webforj.router.security.RouteSecurityContext;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
* Yksinkertainen istuntoon perustuva turvallisuuskonteksti.
*
* <p>
* Tallentaa käyttäjäpään ja roolit HTTP-istuntoon. Tämä on minimaalinen toteutus opetus
* tarkoituksiin.
* </p>
*/
public class SecurityContext implements RouteSecurityContext {
private static final String SESSION_USER_KEY = "security.user";
private static final String SESSION_ROLES_KEY = "security.roles";

Miten se toimii:

  • isAuthenticated() tarkistaa, onko istunnossa käyttäjäpää
  • getPrincipal() noutaa käyttäjätunnuksen istuntotallennuksesta
  • hasRole() tarkistaa, sisältääkö käyttäjän roolijoukko määritellyn roolin
  • getAttribute() / setAttribute() hallitsevat mukautettuja turvallisuusattribuutteja
  • Environment.getSessionAccessor() tarjoaa säikeestä turvallisen pääsyn istuntoon

Vaihe 3: Luo turvallisuusmanageri

Hallitsija koordinoi turvallisuuspäätöksiä. Se laajentaa AbstractRouteSecurityManager-luokkaa, joka käsittelee arvioijaketjuja ja pääsyn eväämistä:

SecurityManager.java
package com.securityplain.security;

import com.webforj.environment.ObjectTable;
import com.webforj.environment.SessionObjectTable;
import com.webforj.router.Router;
import com.webforj.router.security.AbstractRouteSecurityManager;
import com.webforj.router.security.RouteAccessDecision;
import com.webforj.router.security.RouteSecurityConfiguration;
import com.webforj.router.security.RouteSecurityContext;

import java.util.Set;

/**
* Yksinkertainen turvallisuusmanagerin toteutus.
*
* <p>
* Tarjoaa staattisia menetelmiä kirjautumiseen/uloskirjautumiseen ja hallitsee turvallisuuskontekstiä.
* </p>
*/
public class SecurityManager extends AbstractRouteSecurityManager {

Miten se toimii:

  • Laajentaa AbstractRouteSecurityManager perii arvioijaketjun logiikan
  • Tarjoaa getConfiguration() ja getSecurityContext() -toteutukset
  • Lisää login() käyttäjien todennusta varten ja tallentaa kirjautumistiedot istuntoon
  • Lisää logout() tyhjentää istunnon ja ohjaa kirjautumissivulle
  • Käyttää SessionObjectTable yksinkertaista istuntotallennusta varten
  • Tallentaa itsensä ObjectTable sovelluksen laajuista käyttöä varten

Vaihe 4: Liitä kaikki käynnistyksessä

Rekisteröijä yhdistää kaikki osat, kun sovellus käynnistyy:

SecurityRegistrar.java
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;

/**
* Rekisteröi reitin turvallisuuskomponentit sovelluksen käynnistämisen aikana.
*
* <p>
* Määritys turvallisuusmanagerista ja arvioijista reitittimen kanssa.
* </p>
*/
@AppListenerPriority(1)
public class SecurityRegistrar implements AppLifecycleListener {

/**
* {@inheritDoc}
*/
@Override
public void onWillRun(App app) {
// Luo turvallisuusmanageri
SecurityManager securityManager = new SecurityManager();
securityManager.saveCurrent(securityManager);

// Rekisteröi sisäänrakennetut arvioijat prioriteetit
securityManager.registerEvaluator(new DenyAllEvaluator(), 0);
securityManager.registerEvaluator(new AnonymousAccessEvaluator(), 1);
securityManager.registerEvaluator(new PermitAllEvaluator(), 2);
securityManager.registerEvaluator(new RolesAllowedEvaluator(), 3);

// Luo turvallisuustarkkailija ja liitä reitittimeen
RouteSecurityObserver securityObserver = new RouteSecurityObserver(securityManager);
Router router = Router.getCurrent();
if (router != null) {
router.getRenderer().addObserver(securityObserver);
}
}
}

Rekisteröi kuuntelija:

Luo src/main/resources/META-INF/services/com.webforj.AppLifecycleListener seuraavalla sisällöllä:

com.securityplain.security.SecurityRegistrar

Tämä rekisteröi AppLifecycleListener, jotta se ajetaan sovelluksen käynnistyessä.

Miten se toimii:

  • Suoritetaan aikaisessa vaiheessa (@AppListenerPriority(1)) määrittääkseen turvallisuus ennen reittien lataamista
  • Luo turvallisuusmanagerin ja tallentaa sen globaalisti
  • Rekisteröi sisäänrakennetut arvioijat prioriteettijärjestyksessä (alemmat numerot suoritetaan ensin)
  • Luo tarkkailijan, joka keskeyttää navigoinnin
  • Liittää tarkkailijan reitittimeen, jotta turvallisuustarkastukset tapahtuvat automaattisesti

Kun tämä on suoritettu, turvallisuus on aktiivinen kaikessa navigoinnissa.

Käytä toteutustasi

Luo kirjautumisnäkymä

Seuraava näkymä käyttää Login komponenttia.

LoginView.java
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("Kirjaudu sisään")
@AnonymousAccess
public class LoginView extends Composite<Login> {
private 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());
}
}