Flere inngangspunkter i vårsikkerhet

1. Oversikt

I denne raske opplæringen skal vi ta en titt på hvordan du gjør det definere flere inngangspunkter i en Spring Security-applikasjon.

Dette innebærer hovedsakelig å definere flere http blokkerer i en XML-konfigurasjonsfil eller flere HttpSikkerhet tilfeller ved å utvide WebSecurityConfigurerAdapter klasse flere ganger.

2. Maven-avhengigheter

For utvikling trenger vi følgende avhengigheter:

 org.springframework.boot spring-boot-starter-security 2.2.2.RELEASE org.springframework.boot spring-boot-starter-web 2.2.2.RELEASE org.springframework.boot spring-boot-starter-thymeleaf 2.2.2. RELEASE org.springframework.boot spring-boot-starter-test 2.2.2.RELEASE org.springframework.security spring-security-test 5.2.2.RELEASE 

De siste versjonene av fjær-boot-starter-sikkerhet, spring-boot-starter-web, spring-boot-starter-thymeleaf, spring-boot-starter-test, spring-security-test kan lastes ned fra Maven Central.

3. Flere inngangspunkter

3.1. Flere inngangspunkter med flere HTTP-elementer

La oss definere hovedkonfigurasjonsklassen som inneholder en brukerkilde:

@Configuration @EnableWebSecurity public class MultipleEntryPointsSecurityConfig {@Bean public UserDetailsService userDetailsService () kaster unntak {InMemoryUserDetailsManager manager = ny InMemoryUserDetailsManager (); manager.createUser (User .withUsername ("user") .password (encoder (). encode ("userPass")) .roles ("USER"). build ()); manager.createUser (User .withUsername ("admin") .password (encoder (). encode ("adminPass")) .roles ("ADMIN"). build ()); returleder; } @Bean public PasswordEncoder encoder () {return new BCryptPasswordEncoder (); }}

La oss nå se på hvordan vi kan definere flere inngangspunkter i vår sikkerhetskonfigurasjon.

Vi skal bruke et eksempel drevet av grunnleggende godkjenning her, og vi kommer til å gjøre god bruk av det faktum at Spring Security støtter definisjonen av flere HTTP-elementer i våre konfigurasjoner.

Når du bruker Java-konfigurasjon, er måten å definere flere sikkerhetsområder på, å ha flere @Konfigurasjon klasser som utvider WebSecurityConfigurerAdapter baseklasse - hver med sin egen sikkerhetskonfigurasjon. Disse klassene kan være statiske og plasseres i hovedkonfigurasjonen.

Hovedmotivasjonen for å ha flere inngangspunkter i en applikasjon er hvis det er forskjellige typer brukere som har tilgang til forskjellige deler av applikasjonen.

La oss definere en konfigurasjon med tre inngangspunkter, hver med forskjellige tillatelser og autentiseringsmodi:

  • en for administrative brukere som bruker HTTP Basic Authentication
  • en for vanlige brukere som bruker skjemaautentisering
  • og en for gjestebrukere som ikke krever godkjenning

Inngangspunktet som er definert for administrative brukere, sikrer URL-adresser til skjemaet / admin / ** å bare tillate brukere med rollen som ADMIN og krever grunnleggende HTTP-autentisering med et inngangspunkt av typen BasicAuthenticationEntryPoint som er angitt ved hjelp av authenticationEntryPoint () metode:

@Configuration @Order (1) offentlig statisk klasse App1ConfigurationAdapter utvider WebSecurityConfigurerAdapter {@Override-beskyttet ugyldig konfigurering (HttpSecurity http) kaster Unntak {http.antMatcher ("/ admin / **") .authorizeRequests (). AnyRequest (). HasRole (" ADMIN "). Og (). HttpBasic (). AuthenticationEntryPoint (authenticationEntryPoint ()); } @Bean public AuthenticationEntryPoint authenticationEntryPoint () {BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint (); entryPoint.setRealmName ("admin realm"); retur entryPoint; }}

De @Rekkefølge merknad på hver statiske klasse angir rekkefølgen konfigurasjonene vil bli ansett for å finne en som samsvarer med ønsket URL. De rekkefølge verdien for hver klasse må være unik.

Bønnen av typen BasicAuthenticationEntryPoint krever eiendommen virkelige navn være satt.

3.2. Flere inngangspunkter, samme HTTP-element

Deretter la oss definere konfigurasjonen for nettadresser til skjemaet /bruker/** som er tilgjengelige for vanlige brukere med en BRUKER-rolle ved hjelp av skjemaautentisering:

@Configuration @Order (2) offentlig statisk klasse App2ConfigurationAdapter utvider WebSecurityConfigurerAdapter {beskyttet ugyldig konfigurering (HttpSecurity http) kaster unntak {http.antMatcher ("/ user / **") .authorizeRequests (). AnyRequest (). HasRole ("USER" ) .and () // formLogin-konfigurasjon .and () .exceptionHandling () .defaultAuthenticationEntryPointFor (loginUrlauthenticationEntryPointWithWarning (), new AntPathRequestMatcher ("/ user / private / **")) .defaultAuthenticationEntryPointFor (loginUrla) bruker / generell / ** ")); }}

Som vi kan se, er en annen måte å definere inngangspunkter, i tillegg til metoden authenticationEntryPoint (), å bruke defaultAuthenticationEntryPointFor () metode. Dette kan definere flere inngangspunkter som samsvarer med forskjellige forhold basert på en RequestMatcher gjenstand.

De RequestMatcher grensesnittet har implementeringer basert på forskjellige typer forhold, for eksempel matchende bane, medietype eller regexp. I vårt eksempel har vi brukt AntPathRequestMatch til å angi to forskjellige inngangspunkter for URL-adresser til skjemaene / bruker / privat / ** og / bruker / generelt / **.

Deretter må vi definere bønner for inngangspunkter i samme statiske konfigurasjonsklasse:

@Bean public AuthenticationEntryPoint loginUrlauthenticationEntryPoint () {return new LoginUrlAuthenticationEntryPoint ("/ userLogin"); } @Bean public AuthenticationEntryPoint loginUrlauthenticationEntryPointWithWarning () {return new LoginUrlAuthenticationEntryPoint ("/ userLoginWithWarning"); }

Hovedpoenget her er hvordan du setter opp disse flere inngangspunktene - ikke nødvendigvis implementeringsdetaljene til hver enkelt.

I dette tilfellet er inngangspunktene begge av typen LoginUrlAuthenticationEntryPoint, og bruk en annen URL for påloggingsside: /Brukerinnlogging for en enkel påloggingsside og / userLoginWithWarning for en påloggingsside som også viser en advarsel når du prøver å få tilgang til /bruker/ private nettadresser.

Denne konfigurasjonen vil også kreve å definere /Brukerinnlogging og / userLoginWithWarning MVC-kartlegginger og to sider med standard påloggingsskjema.

For skjemaautentisering er det veldig viktig å huske at enhver URL som er nødvendig for konfigurasjonen, slik som URL for påloggingsbehandling, også må følge /bruker/** format eller på annen måte være konfigurert for å være tilgjengelig.

Begge konfigurasjonene ovenfor omdirigerer til a /403 URL hvis en bruker uten riktig rolle prøver å få tilgang til en beskyttet URL.

Vær forsiktig med å bruke unike navn på bønnene, selv om de er i forskjellige statiske klasser, ellers vil den ene overstyre den andre.

3.3. Nytt HTTP-element, ingen inngangspunkter

Til slutt, la oss definere den tredje konfigurasjonen for URL-adresser i skjemaet /gjest/** som vil tillate alle typer brukere, inkludert uautentiserte brukere:

@Configuration @ Order (3) offentlig statisk klasse App3ConfigurationAdapter utvider WebSecurityConfigurerAdapter {beskyttet ugyldig konfigurering (HttpSecurity http) kaster unntak {http.antMatcher ("/ gjest / **"). AuthorizeRequests (). AnyRequest (). PermitAll (); }}

3.4. XML-konfigurasjon

La oss ta en titt på den tilsvarende XML-konfigurasjonen for de tre HttpSikkerhet forekomster i forrige avsnitt.

Som forventet vil dette inneholde tre separate XML blokker.

For / admin / ** URLer XML-konfigurasjonen vil bruke inngangssted-ref attributt av http-grunnleggende element:

Merknad her er at hvis du bruker XML-konfigurasjon, må rollene være av skjemaet ROLE_.

Konfigurasjonen for /bruker/** URL-er må deles opp i to http blokker i xml fordi det ikke er noen direkte ekvivalent med defaultAuthenticationEntryPointFor () metode.

Konfigurasjonen for URL-er / bruker / generelt / ** er:

  // konfigurasjon for skjemainnlogging 

For / bruker / privat / ** URL-er vi kan definere en lignende konfigurasjon:

  // konfigurasjon for skjemainnlogging 

For /gjest/** URL-er vi har http element:

Også viktig her er at minst en XML blokken må samsvare med / ** mønsteret.

4. Få tilgang til beskyttede nettadresser

4.1. MVC-konfigurasjon

La oss lage forespørselstilknytninger som samsvarer med URL-mønstrene vi har sikret:

@Controller public class PagesController {@GetMapping ("/ admin / myAdminPage") public String getAdminPage () {return "multipleHttpElems / myAdminPage"; } @GetMapping ("/ user / general / myUserPage") offentlig streng getUserPage () {returner "multipleHttpElems / myUserPage"; } @GetMapping ("/ user / private / myPrivateUserPage") public String getPrivateUserPage () {return "multipleHttpElems / myPrivateUserPage"; } @GetMapping ("/ guest / myGuestPage") offentlig streng getGuestPage () {returner "multipleHttpElems / myGuestPage"; } @GetMapping ("/ multipleHttpLinks") offentlig streng getMultipleHttpLinksPage () {return "multipleHttpElems / multipleHttpLinks"; }}

De / multipleHttpLinks mapping vil returnere en enkel HTML-side med lenker til de beskyttede URL-ene:

Administratorside Brukerside Privat brukerside Gjesteside

Hver av HTML-sidene som tilsvarer de beskyttede URL-ene, har en enkel tekst og en tilbakekobling:

Velkommen admin! Tilbake til lenker

4.2. Initialiserer applikasjonen

Vi vil kjøre eksemplet vårt som en Spring Boot-applikasjon, så la oss definere en klasse med hovedmetoden:

@SpringBootApplication public class MultipleEntryPointsApplication {public static void main (String [] args) {SpringApplication.run (MultipleEntryPointsApplication.class, args); }}

Hvis vi vil bruke XML-konfigurasjonen, må vi også legge til @ImportResource ({“classpath *: spring-security-multiple-entry.xml”}) kommentar til hovedklassen vår.

4.3. Testing av sikkerhetskonfigurasjonen

La oss sette opp en JUnit-testklasse som vi kan bruke til å teste våre beskyttede nettadresser:

@RunWith (SpringRunner.class) @WebAppConfiguration @SpringBootTest (klasser = MultipleEntryPointsApplication.class) offentlig klasse MultipleEntryPointsTest {@Autowired privat WebApplicationContext wac; @Autowired private FilterChainProxy springSecurityFilterChain; private MockMvc mockMvc; @Før offentlige ugyldige oppsett () {this.mockMvc = MockMvcBuilders.webAppContextSetup (this.wac) .addFilter (springSecurityFilterChain) .build (); }}

La oss deretter teste nettadressene ved hjelp av admin bruker.

Når du ber om / admin / adminSide URL uten HTTP Basic Authentication, bør vi forvente å motta en uautorisert statuskode, og etter at autentiseringen er lagt til, skal statuskoden være 200 OK.

Hvis du prøver å få tilgang til / bruker / brukerside URL med administratorbrukeren, vi skal motta status 302 forbudt:

@Test offentlig ugyldig når TestAdminCredentials_thenOk () kaster unntak {mockMvc.perform (get ("/ admin / myAdminPage")). Og Expect (status (). IsUnauthorized ()); mockMvc.perform (get ("/ admin / myAdminPage") .with (httpBasic ("admin", "adminPass"))). ogExpect (status (). isOk ()); mockMvc.perform (get ("/ user / myUserPage") .med (user ("admin"). passord ("adminPass"). roller ("ADMIN"))). og Expect (status (). isForbidden ()); }

La oss lage en lignende test ved hjelp av den vanlige brukerlegitimasjonen for å få tilgang til URL-ene:

@Test offentlig ugyldig når TestUserCredentials_thenOk () kaster unntak {mockMvc.perform (get ("/ user / general / myUserPage")). Og Expect (status (). IsFound ()); mockMvc.perform (get ("/ user / general / myUserPage") .med (user ("user"). passord ("userPass"). roller ("USER"))). og Expect (status (). isOk () ); mockMvc.perform (get ("/ admin / myAdminPage") .with (user ("user"). password ("userPass") .roller ("USER"))). andExpect (status (). isForbidden ()); }

I den andre testen kan vi se at manglende skjemaautentisering vil resultere i statusen 302 Fant i stedet for Uautorisert, da Spring Security vil omdirigere til påloggingsskjemaet.

Til slutt, la oss lage en test der vi får tilgang til / gjest / gjesteside URL vil alle tre typer autentisering og bekrefte at vi mottar en status på 200 OK:

@Test offentlig ugyldig givenAnyUser_whenGetGuestPage_thenOk () kaster unntak {mockMvc.perform (get ("/ guest / myGuestPage")). AndExpect (status (). IsOk ()); mockMvc.perform (get ("/ guest / myGuestPage") .med (bruker ("bruker"). passord ("userPass"). roller ("BRUKER"))). og Forvent (status (). isOk ()); mockMvc.perform (get ("/ guest / myGuestPage") .with (httpBasic ("admin", "adminPass"))). og Expect (status (). isOk ()); }

5. Konklusjon

I denne opplæringen har vi demonstrert hvordan du konfigurerer flere inngangspunkter når du bruker Spring Security.

Den komplette kildekoden for eksemplene finner du på GitHub. For å kjøre applikasjonen, fjern kommentar fra MultipleEntryPointsApplicationstartklasse tag i pom.xml og kjør kommandoen mvn spring-boot: run, får deretter tilgang til / multipleHttpLinks URL.

Merk at det ikke er mulig å logge av når du bruker HTTP Basic Authentication, så du må lukke og åpne nettleseren på nytt for å fjerne denne autentiseringen.

For å kjøre JUnit-testen, bruk den definerte Maven-profilen entryPoints med følgende kommando:

mvn ren installasjon -PentryPoints


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