Spring Security 5 reaktív alkalmazásokhoz

1. Bemutatkozás

Ebben a cikkben a Spring Security 5 keretrendszer új funkcióit tárjuk fel a reaktív alkalmazások biztonságának biztosítása érdekében. Ez a kiadás összhangban van az 5. tavasszal és a tavaszi csomagtartóval.

Ebben a cikkben nem részletezzük magukat a reaktív alkalmazásokat, amelyek a Spring 5 keretrendszer újdonságai. További részletekért olvassa el az Intro to Reactor Core című cikket.

2. Maven Setup

A Spring Boot indítókat használjuk a projekt indításához a szükséges függőségekkel együtt.

Az alapbeállításhoz szülődeklaráció, webindító és biztonsági indítófüggőség szükséges. Szükségünk lesz a tavaszi biztonsági teszt keretrendszerre is:

 org.springframework.boot spring-boot-starter-parent 2.2.6.RELEASE org.springframework.boot spring-boot-starter-webflux org.springframework.boot spring-boot-starter-security org.springframework.security spring-security- teszt 

Megnézhetjük a Spring Boot security starter aktuális verzióját a Maven Central-nál.

3. Projekt beállítása

3.1. A reaktív alkalmazás indítása

Nem fogjuk használni a szabványt @SpringBootApplication konfigurálásához, hanem állítson be egy Netty-alapú webszervert. A Netty aszinkron NIO alapú keretrendszer, amely jó alapot jelent a reaktív alkalmazásokhoz.

A @EnableWebFlux az annotáció lehetővé teszi a szokásos Spring Web Reactive konfigurációt az alkalmazáshoz:

@ComponentScan (basePackages = {"com.baeldung.security"}) @EnableWebFlux public class SpringSecurity5Application {public static void main (String [] args) {try (AnnotationConfigApplicationContext context = new AnnotationConfigApplecComplex.SplicationContext NettyContext.class) .onClose (). Block (); }}

Itt létrehozunk egy új alkalmazáskörnyezetet, és hívással várjuk, amíg Netty leáll .onClose (). block () lánc a Netty-kontextusban.

Miután Netty leállt, a kontextus automatikusan bezárul a erőforrásokkal próbálkozzon Blokk.

Létre kell hoznunk egy Netty-alapú HTTP szervert, egy kezelőt a HTTP kérésekhez, valamint az adaptert a kiszolgáló és a kezelő között:

@Bean public NettyContext nettyContext (ApplicationContext context) {HttpHandler handler = WebHttpHandlerBuilder .applicationContext (context) .build (); ReactorHttpHandlerAdapter adapter = új ReactorHttpHandlerAdapter (kezelő); HttpServer httpServer = HttpServer.create ("localhost", 8080); return httpServer.newHandler (adapter) .block (); }

3.2. Tavaszi biztonsági konfigurációs osztály

Az alap tavaszi biztonsági konfigurációnkhoz létrehozunk egy konfigurációs osztályt - SecurityConfig.

A WebFlux támogatás engedélyezéséhez a Spring Security 5-ben csak a @EnableWebFluxSecurity kommentár:

@EnableWebFluxSecurity public class SecurityConfig {// ...}

Most kihasználhatjuk az osztály előnyeit ServerHttpSecurity a biztonsági konfigurációnk kiépítéséhez.

Ez az osztály az 5. tavasz újdonsága. Hasonló HttpBiztonság builder, de csak a WebFlux alkalmazásoknál engedélyezett.

A ServerHttpSecurity már előre be van állítva néhány épeszű alapértelmezettel, így ezt a konfigurációt teljesen kihagyhatnánk. De kezdőként a következő minimális konfigurációt fogjuk megadni:

@Bean public SecurityWebFilterChain securitygWebFilterChain (ServerHttpSecurity http) {return http.authorizeExchange () .anyExchange (). Hitelesített () .és (). Build (); }

Szükségünk lesz egy felhasználói adatok szolgáltatására is. A Spring Security kényelmes modellalkotót és a felhasználói részletek szolgáltatás memóriájában történő megvalósítását biztosítja számunkra:

@Bean public MapReactiveUserDetailsService userDetailsService () {UserDetails user = Felhasználó .WithUsername ("felhasználó") .jelszó (passwordEncoder (). Encode ("jelszó")) .roles ("USER") .build (); return new MapReactiveUserDetailsService (felhasználó); }

Mivel reaktív földön vagyunk, a felhasználói adatok szolgáltatásának is reaktívnak kell lennie. Ha megnézzük a ReactiveUserDetailsService felület, meglátjuk, hogy az findByUsername metódus valójában a Monó kiadó:

nyilvános felület ReactiveUserDetailsService {Mono findByUsername (String felhasználónév); }

Most futtathatjuk az alkalmazásunkat, és megfigyelhetünk egy szokásos HTTP alap hitelesítési űrlapot.

4. Stílusú bejelentkezési űrlap

A Spring Security 5 apró, de feltűnő fejlesztése egy új stílusú bejelentkezési űrlap, amely a Bootstrap 4 CSS keretrendszert használja. A bejelentkezési űrlap stíluslapjai a CDN-re mutatnak, így a javulást csak akkor látjuk, ha csatlakozik az internethez.

Az új bejelentkezési űrlap használatához adjuk hozzá a megfelelőt formLogin () építő módszer a ServerHttpSecurity építész:

public SecurityWebFilterChain securitygWebFilterChain (ServerHttpSecurity http) {return http.authorizeExchange () .anyExchange (). hitelesített () .és (). formLogin () .és (). build (); }

Ha most megnyitjuk az alkalmazás főoldalát, látni fogjuk, hogy sokkal jobban néz ki, mint az alapértelmezett űrlap, amelyet a Spring Security korábbi verziói óta megszokhattunk:

Ne feledje, hogy ez nem gyártásra kész forma, de az alkalmazásunk jó bootstrapja.

Ha most bejelentkezünk, majd a // localhost: 8080 / logout URL-re megyünk, akkor megjelenik a kijelentkezés megerősítő űrlapja, amely szintén stílusú.

5. A reaktív vezérlő biztonsága

Ha látni akar valamit a hitelesítési űrlap mögött, valósítsunk meg egy egyszerű reaktív vezérlőt, amely üdvözli a felhasználót:

@RestController nyilvános osztály GreetController {@GetMapping ("/") nyilvános mono üdvözlet (mono fő) {return principál .map (Principal :: getName) .map (név -> String.format ("Hello,% s", név) ); }}

Bejelentkezés után meglátjuk az üdvözletet. Vegyünk fel egy másik reaktív kezelőt, amelyhez csak az admin hozzáférhet:

@GetMapping ("/ admin") nyilvános mono greetAdmin (mono fő) {return principál .map (Principal :: getName) .map (név -> String.format ("Adminisztrátori hozzáférés:% s", név)); }

Most hozzunk létre egy második felhasználót a szerepkörrel ADMIN: a felhasználói adatok szolgáltatásunkban:

UserDetails admin = User.withDefaultPasswordEncoder () .username ("admin") .password ("jelszó") .roles ("ADMIN") .build ();

Most hozzáadhatunk egy illesztő szabályt az adminisztrátori URL-hez, amely megköveteli, hogy a felhasználó rendelkezzen a ROLE_ADMIN hatóság.

Ne feledje, hogy a mérkőzõket a .anyExchange () lánchívás. Ez a felhívás minden más URL-re vonatkozik, amelyekre még nem terjedtek ki más egyeztetők:

return http.authorizeExchange () .pathMatchers ("/ admin"). hasAuthority ("ROLE_ADMIN") .anyExchange (). hitelesítve () .és (). formLogin () .és (). build ();

Ha most bejelentkezünk felhasználó vagy admin, látni fogjuk, hogy mindketten megfigyelik a kezdeti üdvözlést, mivel minden hitelesített felhasználó számára hozzáférhetővé tettük.

De csak a admin a felhasználó meglátogathatja a // localhost: 8080 / admin URL-t, és megnézheti üdvözletét.

6. Reaktív módszer biztonsága

Láttuk, hogyan tudjuk biztosítani az URL-eket, de mi a helyzet a módszerekkel?

A reaktív módszerek módszeralapú biztonságának engedélyezéséhez csak hozzá kell adnunk a @EnableReactiveMethodSecurity annotáció a mi SecurityConfig osztály:

@EnableWebFluxSecurity @EnableReactiveMethodSecurity public class SecurityConfig {// ...}

Hozzunk létre egy reaktív üdvözlő szolgáltatást a következő tartalommal:

@Service nyilvános osztály GreetService {public Mono greet () {return Mono.just ("Hello from service!"); }}

Injektálhatjuk a vezérlőbe, lépjünk a // localhost: 8080 / greetService oldalra, és láthatjuk, hogy valóban működik:

@RestController public class GreetController {private GreetService greetService @GetMapping ("/ greetService") public Mono greetService () {return greetService.greet (); } // szabványos kivitelezők ...}

De ha most hozzáadjuk a @PreAuthorize a szolgáltatás metódusának megjegyzése a ADMIN szerepkör, akkor az üdvözlő szolgáltatás URL-je nem lesz elérhető a rendes felhasználók számára:

@Service public class GreetService {@PreAuthorize ("hasRole ('ADMIN')") public Mono greet () {// ...}

7. Gúnyolódó felhasználók a tesztekben

Nézzük meg, milyen egyszerű tesztelni a reaktív tavaszi alkalmazást.

Először létrehozunk egy tesztet egy injektált alkalmazáskörnyezettel:

@ContextConfiguration (class = SpringSecurity5Application.class) public class SecurityTest {@Autowired ApplicationContext context; // ...}

Most létrehozunk egy egyszerű reaktív webes tesztklienst, amely az 5. tavaszi tesztkeret egyik jellemzője:

@A nyilvános void beállítása előtt () {this.rest = WebTestClient .bindToApplicationContext (this.context) .configureClient () .build (); }

Ez lehetővé teszi számunkra, hogy gyorsan ellenőrizzük, hogy az illetéktelen felhasználót átirányítják-e alkalmazásunk főoldaláról a bejelentkezési oldalra:

@Test public void whenNoCredentials_thenRedirectToLogin () {this.rest.get () .uri ("/") .exchange () .expectStatus (). Is3xxRedirection (); }

Ha most hozzáadjuk a @MockWithUser egy vizsgálati módszer kommentárja, hitelesített felhasználót tudunk biztosítani ehhez a módszerhez.

A felhasználó bejelentkezési neve és jelszava a következő lesz: felhasználó és Jelszó illetve a szerepe az FELHASZNÁLÓ. Ez természetesen mind konfigurálható a @MockWithUser annotációs paraméterek.

Most ellenőrizhetjük, hogy az engedélyezett felhasználó látja-e az üdvözletet:

@Test @WithMockUser public void whenHasCredentials_thenSeesGreeting () {this.rest.get () .uri ("/") .exchange () .expectStatus (). IsOk () .expectBody (String.class) .isEqualTo ("Helló, felhasználó "); }

A @WithMockUser az annotáció a Spring Security 4 óta elérhető. A Spring Security 5-ben azonban frissítették a reaktív végpontokat és módszereket is.

8. Következtetés

Ebben az oktatóanyagban felfedeztük a készülő Spring Security 5 kiadás új funkcióit, különösen a reaktív programozási arénában.

Mint mindig, a cikk forráskódja elérhető a GitHubon.