Siirry pääsisältöön

Custom Implementation Example

Avaa ChatGPT:ssä

Tämä opas käy läpi täydellisen mukautetun turvallisuustoteutuksen luomisen, joka käyttää istuntopohjaista todennusta. Opit, miten neljä keskeistä rajapintaa toimivat yhdessä toteuttamalla ne alusta alkaen.

Useimmat sovellukset voivat käyttää Spring Securityä

Spring Security -integraatio määrittää automaattisesti kaiken, mitä tässä on esitetty. Rakenna mukautettu turvallisuus vain, 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 HTTP-istuntojen avulla
  • SecurityManager - Koordinoi turvallisuustarkastuksia ja tarjoaa kirjautumis-/uloskirjautumismahdollisuudet
  • SecurityRegistrar - Yhdistää kaiken sovelluksen käynnistyksessä

Tässä esimerkissä käytetään istuntopohjaista tallennusta, mutta voit toteuttaa samat rajapinnat käyttämällä tietokantakyselyitä, LDAP:ia tai mitä tahansa muuta todennuspohjaa.

Miten osat toimivat yhdessä

Virtaus:

  1. SecurityRegistrar toimii käynnistyksen aikana, luo hallitsijan, rekisteröi arvioijat ja liittää tarkkailijan
  2. SecurityManager koordinoi kaiken - se antaa kontekstin ja määrityksen arvioijille
  3. SecurityContext vastaa kysymykseen "Kuka on kirjautuneena?" lukemalla HTTP-istunnoista
  4. SecurityConfiguration vastaa kysymykseen "Minne ohjata?" kirjautuminen ja pääsy hylätty -sivuille
  5. Evaluators tekevät pääsypäätöksiä käyttämällä kontekstia ja määritystä

Vaihe 1: Määritä turvallisuusmääritys

Määritys kertoo turvallisuusjärjestelmälle, miten sen tulisi toimia ja minne käyttäjät tulisi ohjata:

SecurityConfiguration.java
package com.securityplain.security;

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

/**
* Turvallisuusmääritys sovellukselle.
*
* <p>
* Määrittelee, minne käyttäjät ohjataan, kun todennus on vaadittu tai pääsy on hylätty.
* </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 niitä ole merkitty (käytä true, jos haluat vaatia todennusta kaikilla reiteillä oletuksena)
  • /login - Minne toteamattomat käyttäjät menevät
  • /access-denied - Minne tunnistetut 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 istuntopohjainen turvallisuuskonteksti.
*
* <p>
* Tallentaa käyttäjän pääsyn ja roolit HTTP-istunnossa. 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 käyttäjän pääsytieto olemassa istunnossa
  • getPrincipal() palauttaa käyttäjänimen istuntoTallennuksesta
  • hasRole() tarkistaa, sisältääkö käyttäjän roolijoukko määritetyn roolin
  • getAttribute() / setAttribute() hallinnoi mukautettuja turvallisuusominaisuuksia
  • Environment.getSessionAccessor() tarjoaa säikeen turvallisen pääsyn istuntoon

Vaihe 3: Luo turvallisuuden hallinta

Hallinta koordinoi turvallisuuspäätöksiä. Se laajentaa AbstractRouteSecurityManager-luokkaa, joka käsittelee arvioijaketjuja ja pääsyn hylkää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 turvallisuuden hallinta toteutus.
*
* <p>
* Tarjoaa staattisia menetelmiä sisäänkirjautumiseen/uloskirjautumiseen ja hallitsee turvallisuuskontekstiä.
* </p>
*/
public class SecurityManager extends AbstractRouteSecurityManager {

Miten se toimii:

  • Laajentaa AbstractRouteSecurityManager saadakseen arvioijaketjun logiikan
  • Tarjoaa getConfiguration() ja getSecurityContext() toteutukset
  • Lisää login() autentikoimaan käyttäjiä ja tallentamaan todennustiedot istuntoon
  • Lisää logout() tyhjentämään istunnon ja ohjaamaan kirjautumissivulle
  • Käyttää SessionObjectTable yksinkertaiseen istuntotallennukseen
  • Tallentaa itsensä ObjectTable sovelluksen laajuiseen käyttöön

Vaihe 4: Yhdistä kaikki käynnistyksessä

Rekisteröijä yhdistää kaikki osat sovelluksen käynnistyessä:

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äynnistyksen aikana.
*
* <p>
* Määrittelee turvallisuuden hallinnan ja arvioijat reitittimen kanssa.
* </p>
*/
@AppListenerPriority(1)
public class SecurityRegistrar implements AppLifecycleListener {

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

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

// Luo turvallisuustarkkailija ja liitä se 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 sinun AppLifecycleListener, jotta se toimii sovelluksen käynnistyksessä.

Miten se toimii:

  • Toimii varhain (@AppListenerPriority(1)) määrittämään turvallisuuden ennen reittien lataamista
  • Luo turvallisuuden hallinnan ja tallentaa sen globaalisti
  • Rekisteröi sisäänrakennetut arvioijat prioriteetti järjestyksessä (alhaisemmat numerot suoritetaan ensin)
  • Luo tarkkailijan, joka keskeyttää navigoinnin
  • Liittää tarkkailijan reitittimeen siten, että turvallisuustarkastukset tapahtuvat automaattisesti

Kun tämä on suoritettu, turvallisuus on aktivoitu kaikelle navigoinnille.

Toteuttamisesi käyttäminen

Luo kirjautumissivu

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("Kirjautuminen")
@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());
}
}