Spring Security 5 for reaktive applikasjoner

1. Introduksjon

I denne artikkelen vil vi utforske nye funksjoner i Spring Security 5-rammeverket for å sikre reaktive applikasjoner. Denne utgivelsen er justert med Spring 5 og Spring Boot 2.

I denne artikkelen vil vi ikke gå i detaljer om selve reaktive applikasjoner, som er en ny funksjon i Spring 5-rammeverket. Husk å sjekke artikkelen Intro to Reactor Core for mer informasjon.

2. Maven-oppsett

Vi bruker vårstarter for å starte prosjektet sammen med alle nødvendige avhengigheter.

Det grunnleggende oppsettet krever en overordnet erklæring, nettstarter og sikkerhetsstarteravhengighet. Vi trenger også Spring Security test-rammeverket:

 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- test test 

Vi kan sjekke ut den nåværende versjonen av Spring Boot-sikkerhetsstarter på Maven Central.

3. Prosjektoppsett

3.1. Bootstrapping den reaktive applikasjonen

Vi bruker ikke standarden @SpringBootApplication konfigurasjon, men konfigurer i stedet en Netty-basert webserver. Netty er et asynkront NIO-basert rammeverk som er et godt grunnlag for reaktive applikasjoner.

De @EnableWebFlux kommentar muliggjør standard Spring Web Reactive-konfigurasjon for applikasjonen:

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

Her oppretter vi en ny applikasjonskontekst og venter på at Netty stenger av ved å ringe .onClose (). blokk () kjede på Netty-sammenheng.

Etter at Netty er stengt, lukkes konteksten automatisk ved hjelp av prøv-med-ressurser blokkere.

Vi må også opprette en Netty-basert HTTP-server, en behandler for HTTP-forespørslene og adapteren mellom serveren og behandleren:

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

3.2. Vårs sikkerhetskonfigurasjonsklasse

For vår grunnleggende Spring Security-konfigurasjon oppretter vi en konfigurasjonsklasse - SecurityConfig.

For å aktivere WebFlux-støtte i Spring Security 5, trenger vi bare å spesifisere @EnableWebFluxSecurity kommentar:

@EnableWebFluxSecurity offentlig klasse SecurityConfig {// ...}

Nå kan vi dra nytte av klassen ServerHttpSecurity for å bygge vår sikkerhetskonfigurasjon.

Denne klassen er en ny funksjon i vår 5. Det ligner på HttpSikkerhet byggherre, men den er bare aktivert for WebFlux-applikasjoner.

De ServerHttpSecurity er allerede forhåndskonfigurert med noen fornuftige standarder, så vi kan hoppe over denne konfigurasjonen helt. Men for det første vil vi gi følgende minimale konfigurasjon:

@Bean public SecurityWebFilterChain securitygWebFilterChain (ServerHttpSecurity http) {return http.authorizeExchange () .anyExchange (). Autentisert () .and (). Build (); }

Vi trenger også en brukerinformasjonstjeneste. Spring Security gir oss en praktisk mock user builder og en implementering i minnet av brukerdetaljetjenesten:

@Bean public MapReactiveUserDetailsService userDetailsService () {UserDetails user = User .withUsername ("user") .password (passwordEncoder (). Encode ("password")) .roles ("USER") .build (); returner ny MapReactiveUserDetailsService (bruker); }

Siden vi er i reaktivt land, bør brukerdetaljetjenesten også være reaktiv. Hvis vi sjekker ut ReactiveUserDetailsService grensesnitt, vi får se at det er findByUsername metode returnerer faktisk en Mono forlegger:

offentlig grensesnitt ReactiveUserDetailsService {Mono findByUsername (String username); }

Nå kan vi kjøre applikasjonen vår og observere et vanlig HTTP-grunnleggende autentiseringsskjema.

4. Formet påloggingsskjema

En liten, men slående forbedring i Spring Security 5 er et nytt utformet påloggingsskjema som bruker Bootstrap 4 CSS-rammeverket. Stilarkene i påloggingsskjemaet lenker til CDN, så vi ser bare forbedringen når vi er koblet til Internett.

For å bruke det nye påloggingsskjemaet, la oss legge til det tilsvarende formLogin () byggemetode til ServerHttpSecurity bygger:

offentlig SecurityWebFilterChain securitygWebFilterChain (ServerHttpSecurity http) {return http.authorizeExchange () .anyExchange (). autentisert (). og (). formLogin (). og (). build (); }

Hvis vi nå åpner hovedsiden i applikasjonen, ser vi at den ser mye bedre ut enn standardskjemaet vi er vant med siden tidligere versjoner av Spring Security:

Merk at dette ikke er et produksjonsklar skjema, men det er en god oppstartsramme for applikasjonen vår.

Hvis vi nå logger inn og deretter går til // localhost: 8080 / logout URL, ser vi bekreftelseskjemaet for avlogging, som også er utformet.

5. Reaktiv kontrollersikkerhet

For å se noe bak autentiseringsskjemaet, la oss implementere en enkel reaktiv kontroller som hilser på brukeren:

@RestController public class GreetController {@GetMapping ("/") public Mono greet (Mono principal) {return principal .map (Principal :: getName) .map (name -> String.format ("Hello,% s", name) ); }}

Etter innlogging ser vi hilsenen. La oss legge til en annen reaktiv behandler som bare er tilgjengelig av admin:

@GetMapping ("/ admin") offentlig Mono greetAdmin (Mono rektor) {retur rektor .map (rektor :: getName) .map (navn -> String.format ("Admin tilgang:% s", navn)); }

La oss nå opprette en ny bruker med rollen ADMIN: i vår brukerinformasjonstjeneste:

UserDetails admin = User.withDefaultPasswordEncoder (). Brukernavn ("admin") .passord ("passord") .roles ("ADMIN") .build ();

Vi kan nå legge til en matcherregel for admin-URL som krever at brukeren har ROLE_ADMIN autoritet.

Merk at vi må sette matchere før .any Exchange () kjedeanrop. Denne samtalen gjelder alle andre nettadresser som ennå ikke ble dekket av andre matchere:

returner http.authorizeExchange () .pathMatchers ("/ admin"). hasAuthority ("ROLE_ADMIN") .anyExchange (). autentisert () .and (). formLogin () .and (). build ();

Hvis vi nå logger på med bruker eller admin, ser vi at de begge overholder innledende hilsener, ettersom vi har gjort den tilgjengelig for alle autentiserte brukere.

Men bare den admin brukeren kan gå til // localhost: 8080 / admin URL og se hilsenen hennes.

6. Sikkerhet med reaktiv metode

Vi har sett hvordan vi kan sikre nettadressene, men hva med metoder?

For å aktivere metodebasert sikkerhet for reaktive metoder, trenger vi bare å legge til @EnableReactiveMethodSecurity kommentar til vår SecurityConfig klasse:

@EnableWebFluxSecurity @EnableReactiveMethodSecurity offentlig klasse SecurityConfig {// ...}

La oss nå lage en reaktiv hilsen-tjeneste med følgende innhold:

@Service offentlig klasse GreetService {offentlig Mono hilsen () {return Mono.just ("Hei fra tjenesten!"); }}

Vi kan injisere den i kontrolleren, gå til // localhost: 8080 / greetService og se at den faktisk fungerer:

@RestController offentlig klasse GreetController {private GreetService greetService @GetMapping ("/ greetService") offentlig Mono greetService () {return greetService.greet (); } // standardkonstruktører ...}

Men hvis vi nå legger til @PreAuthorize kommentar om tjenestemetoden med ADMIN rolle, vil ikke hilsen-tjenestens URL være tilgjengelig for en vanlig bruker:

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

7. Spottende brukere i tester

La oss sjekke ut hvor enkelt det er å teste vår reaktive vårapplikasjon.

Først oppretter vi en test med en injisert applikasjonskontekst:

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

Nå setter vi opp en enkel reaktiv webtestklient, som er en funksjon i Spring 5-testrammeverket:

@Før offentlige ugyldige oppsett () {this.rest = WebTestClient .bindToApplicationContext (this.context) .configureClient () .build (); }

Dette lar oss raskt sjekke at den uautoriserte brukeren blir omdirigert fra hovedsiden til applikasjonen vår til påloggingssiden:

@Test offentlig ugyldig nårNoCredentials_thenRedirectToLogin () {this.rest.get () .uri ("/") .exchange () .expectStatus (). Is3xxRedirection (); }

Hvis vi nå legger til @MockWithUser kommentar til en testmetode, kan vi tilby en autentisert bruker for denne metoden.

Innloggingen og passordet til denne brukeren vil være bruker og passord henholdsvis, og rollen er BRUKER. Dette kan selvfølgelig alt konfigureres med @MockWithUser merknadsparametere.

Nå kan vi sjekke at den autoriserte brukeren ser hilsenen:

@Test @WithMockUser offentlig ugyldig nårHasCredentials_thenSeesGreeting () {this.rest.get () .uri ("/") .exchange () .expectStatus (). IsOk () .expectBody (String.class) .isEqualTo ("Hello, user "); }

De @WithMockUser kommentar er tilgjengelig siden Spring Security 4. I Spring Security 5 ble den imidlertid også oppdatert for å dekke reaktive endepunkter og metoder.

8. Konklusjon

I denne veiledningen har vi oppdaget nye funksjoner i den kommende Spring Security 5-utgivelsen, spesielt i den reaktive programmeringsarenaen.

Som alltid er kildekoden for artikkelen tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found