Spring Security 5 - OAuth2-pålogging

1. Oversikt

Spring Security 5 introduserer en ny OAuth2LoginConfigurer klasse som vi kan bruke til å konfigurere en ekstern autorisasjonsserver.

I denne artikkelen, Vi utforsker noen av de forskjellige konfigurasjonsalternativene som er tilgjengelige for oauth2Login () element.

2. Maven-avhengigheter

I et Spring Boot-prosjekt er alt vi trenger å legge til starteren spring-boot-starter-oauth2-client:

 org.springframework.boot spring-boot-starter-oauth2-client 2.3.3.RELEASE 

I et ikke-oppstartsprosjekt, i tillegg til standardavhengighetene for vår og vår, må vi også eksplisitt legge til vår-sikkerhet-oauth2-klient og vår-sikkerhet-oauth2-jose avhengigheter:

 org.springframework.security spring-security-oauth2-client 5.3.4.RELEASE org.springframework.security spring-security-oauth2-jose 5.3.4.RELEASE 

3. Oppsett av klienter

I et Spring Boot-prosjekt er alt vi trenger å gjøre å legge til noen få standardegenskaper for hver klient vi vil konfigurere.

La oss sette opp prosjektet vårt for pålogging med klienter som er registrert hos Google og Facebook som autentiseringsleverandører.

3.1. Få klientlegitimasjon

For å oppnå klientlegitimasjon for Google OAuth2-autentisering, gå videre til Google API-konsollen - seksjonen "Legitimasjonsinformasjon".

Her oppretter vi legitimasjon av typen “OAuth2 Client ID” for webapplikasjonen vår. Dette resulterer i at Google setter opp en klient-ID og hemmelighet for oss.

Vi må også konfigurere en autorisert omdirigerings-URI i Google-konsollen, som er banen brukerne vil bli omdirigert til etter at de har logget inn på Google.

Som standard konfigurerer Spring Boot denne viderekoblings-URI som / login / oauth2 / code / {registrationId}. Derfor legger vi til URI for Google:

// localhost: 8081 / login / oauth2 / code / google

For å få klientlegitimasjonen for autentisering med Facebook, må vi registrere en applikasjon på nettstedet Facebook for Developers og sette opp den tilsvarende URI som en "Gyldig OAuth-omdirigerings-URI":

// localhost: 8081 / login / oauth2 / code / facebook

3.3. Sikkerhetskonfigurasjon

Deretter må vi legge til klientlegitimasjonen til application.properties fil. Spring Security-egenskapene er prefikset med “Spring.security.oauth2.client.registration” etterfulgt av klientnavnet, deretter navnet på klientegenskapen:

spring.security.oauth2.client.registration.google.client-id = spring.security.oauth2.client.registration.google.client-secret = spring.security.oauth2.client.registration.facebook.client-id = spring. security.oauth2.client.registration.facebook.client-secret =

Hvis du legger til disse egenskapene for minst en klient, aktiveres Oauth2ClientAutoConfiguration klasse som setter opp alle nødvendige bønner.

Den automatiske websikkerhetskonfigurasjonen tilsvarer å definere en enkel oauth2Login () element:

@Configuration offentlig klasse SecurityConfig utvider WebSecurityConfigurerAdapter {@Override-beskyttet tomkonfigurasjon (HttpSecurity http) kaster Unntak {http.authorizeRequests () .anyRequest (). Autentisert () .and () .oauth2Login (); }}

Her kan vi se oauth2Login () elementet brukes på en lignende måte som allerede kjent httpBasic () og formLogin () elementer.

Nå, når vi prøver å få tilgang til en beskyttet URL, vil applikasjonen vise en automatisk generert påloggingsside med to klienter:

3.4. Andre klienter

Merk at Spring Security-prosjektet i tillegg til Google og Facebook inneholder også standardkonfigurasjoner for GitHub og Okta. Disse standardkonfigurasjonene gir all nødvendig informasjon for autentisering, og det er det som lar oss bare skrive inn klientinformasjonen.

Hvis vi vil bruke en annen autentiseringsleverandør som ikke er konfigurert i Spring Security, må vi definere full konfigurasjon, med informasjon som autorisasjons-URI og token-URI. Her ser du på standardkonfigurasjonene i Spring Security for å få en ide om egenskapene som trengs.

4. Oppsett i et ikke-oppstartsprosjekt

4.1. Opprette en ClientRegistrationRepository Bønne

Hvis vi ikke jobber med en Spring Boot-applikasjon, må vi definere en ClientRegistrationRepository bønne som inneholder en intern representasjon av klientinformasjonen som eies av autorisasjonsserveren:

@Configuration @EnableWebSecurity @PropertySource ("classpath: application.properties") offentlig klasse SecurityConfig utvider WebSecurityConfigurerAdapter {private static List clients = Arrays.asList ("google", "facebook"); @Bean offentlig ClientRegistrationRepository clientRegistrationRepository () {Listeregistreringer = clients.stream () .map (c -> getRegistration (c)) .filter (registrering -> registrering! = Null) .collect (Collectors.toList ()); returner nytt InMemoryClientRegistrationRepository (registreringer); }}

Her skaper vi en InMemoryClientRegistrationRepository med en liste over ClientRegistration gjenstander.

4.2. Bygning ClientRegistration Objekter

La oss se getRegistration () metode som bygger disse objektene:

privat statisk streng CLIENT_PROPERTY_KEY = "spring.security.oauth2.client.registration."; @Autowired private Environment env; privat ClientRegistration getRegistration (String client) {String clientId = env.getProperty (CLIENT_PROPERTY_KEY + client + ".client-id"); hvis (clientId == null) {return null; } Streng clientSecret = env.getProperty (CLIENT_PROPERTY_KEY + klient + ".client-secret"); hvis (client.equals ("google")) {returner CommonOAuth2Provider.GOOGLE.getBuilder (client) .clientId (clientId) .clientSecret (clientSecret) .build (); } hvis (client.equals ("facebook")) {returner CommonOAuth2Provider.FACEBOOK.getBuilder (client) .clientId (clientId) .clientSecret (clientSecret) .build (); } returner null; }

Her leser vi klientinformasjonen fra et lignende application.properties filen og deretter bruke CommonOauth2Provider enum som allerede er definert i Spring Security for resten av klientegenskapene for Google- og Facebook-klienter.

Hver ClientRegistration forekomst tilsvarer en klient.

4.3. Registrering av ClientRegistrationRepository

Til slutt må vi lage en OAuth2AuthorizedClientService bønne basert på ClientRegistrationRepository bønne og registrer begge hos oauth2Login () element:

@ Override beskyttet ugyldig konfigurasjon (HttpSecurity http) kaster unntak {http.authorizeRequests (). AnyRequest (). Autentisert (). Og () .oauth2Login () .clientRegistrationRepository (clientRegistrationRepository ()) .authorizedClientService (autorisert) } @Bean offentlig OAuth2AuthorizedClientService autorisertClientService () {returner ny InMemoryOAuth2AuthorizedClientService (clientRegistrationRepository ()); }

Som det fremgår her, vi kan bruke clientRegistrationRepository () Metode av oauth2Login () for å registrere et egendefinert registreringslager.

Vi må også definere en tilpasset påloggingsside, da den ikke blir generert lenger. Vi ser mer informasjon om dette i neste avsnitt.

La oss fortsette med videre tilpasning av påloggingsprosessen.

5. Tilpasse oauth2Login ()

Det er flere elementer som OAuth 2-prosessen bruker, og som vi kan tilpasse ved hjelp av oauth2Login () metoder.

Merk at alle disse elementene har standardkonfigurasjoner i Spring Boot, og eksplisitt konfigurasjon er ikke nødvendig.

La oss se hvordan vi kan tilpasse disse i vår konfigurasjon.

5.1. Tilpasset påloggingsside

Selv om Spring Boot genererer en standard innloggingsside for oss, vil vi vanligvis definere vår egen tilpassede side.

La oss starte med å konfigurere en ny innloggings-URL for oauth2Login () ved å brukeloginPage () metode:

@ Override beskyttet ugyldig konfigurasjon (HttpSecurity http) kaster unntak {http.authorizeRequests () .antMatchers ("/ oauth_login") .permitAll () .anyRequest () .authenticated () .and () .oauth2Login () .loginPage ("/ oauth_login "); }

Her har vi satt opp vår innloggings-URL / oauth_login.

Deretter la oss definere en LoginController med en metode som tilordnes til denne URL:

@Controller public class LoginController {private static Streng autorisasjonRequestBaseUri = "oauth2 / autorisasjon"; Kart oauth2AuthenticationUrls = ny HashMap (); @Autowired privat ClientRegistrationRepository clientRegistrationRepository; @GetMapping ("/ oauth_login") public String getLoginPage (Model model) {// ... return "oauth_login"; }}

Denne metoden må sende et kart over klientene som er tilgjengelige og deres autorisasjonsendepunkter til visningen, som vi får fra ClientRegistrationRepository bønne:

public String getLoginPage (Model model) {Iterable clientRegistrations = null; ResolvableType type = ResolvableType.forInstance (clientRegistrationRepository) .as (Iterable.class); if (type! = ResolvableType.NONE && ClientRegistration.class.isAssignableFrom (type.resolveGenerics () [0])) {clientRegistrations = (Iterable) clientRegistrationRepository; } clientRegistrations.forEach (registrering -> oauth2AuthenticationUrls.put (registrering.getClientName (), autorisasjonsanmodningBaseUri + "/" + registrering.getRegistrationId ())); model.addAttribute ("urls", oauth2AuthenticationUrls); returner "oauth_login"; }

Til slutt må vi definere våre oauth_login.html side:

Logg inn med:

Klient

Dette er en enkel HTML-side som viser lenker for å autentisere med hver klient.

Etter å ha lagt til litt styling til det, kan vi endre utseendet på påloggingssiden:

5.2. Tilpasset autentisering suksess og feil atferd

Vi kan kontrollere atferden etter autentisering ved å bruke forskjellige metoder:

  • defaultSuccessUrl () og failureUrl () - å omdirigere brukeren til en gitt URL
  • successHandler () og failureHandler () - å utføre tilpasset logikk etter autentiseringsprosessen

La oss se hvordan vi kan angi egendefinerte URL-er for å omdirigere brukeren til:

.oauth2Login () .defaultSuccessUrl ("/ loginSuccess") .failureUrl ("/ loginFailure");

Hvis brukeren besøkte en sikret side før autentisering, vil de bli omdirigert til den siden etter innlogging. Ellers blir de omdirigert til / loginSuksess.

Hvis vi vil at brukeren alltid skal sendes til / loginSuksess URL, uansett om de var på en sikret side før eller ikke, kan vi bruke metoden defaultSuccessUrl (“/ loginSuccess”, true).

For å bruke en tilpasset behandler, må vi lage en klasse som implementerer AuthenticationSuccessHandler eller AuthenticationFailureHandler grensesnitt, overstyre de arvede metodene, og sett deretter bønnene ved hjelp av suksessHandler () og failureHandler () -metoder.

5.3. Endepunkt for tilpasset autorisasjon

Autorisasjonsendepunktet er endepunktet som Spring Security bruker for å utløse en autorisasjonsforespørsel til den eksterne serveren.

Først, la oss angi nye egenskaper for autorisasjonsendepunktet:

.oauth2Login () .authorizationEndpoint () .baseUri ("/ oauth2 / authorize-client") .authorizationRequestRepository (autorisasjonRequestRepository ());

Her har vi endret baseUri til / oauth2 / authorize-client i stedet for standard / oauth2 / autorisasjon. Vi setter også eksplisitt en autorisasjonsforespørsel () bønne som vi må definere:

@Bean public AuthorizationRequestRepository authorisationRequestRepository () {return new HttpSessionOAuth2AuthorizationRequestRepository (); }

I vårt eksempel har vi brukt implementeringen av våren for vår bønne, men vi kan også tilby en tilpasset.

5.4. Endepunkt for tilpasset token

Token endepunkt behandler tilgangstokener.

La oss eksplisitt konfigurere tokenEndpoint ()med standard responsklientimplementering:

.oauth2Login () .tokenEndpoint () .accessTokenResponseClient (accessTokenResponseClient ());

Og her er svarklientbønnen:

@Bean public OAuth2AccessTokenResponseClient accessTokenResponseClient () {return new NimbusAuthorizationCodeTokenResponseClient (); }

Denne konfigurasjonen er den samme som standard og bruker Spring-implementeringen som er basert på utveksling av en autorisasjonskode med leverandøren.

Selvfølgelig kan vi også erstatte en tilpasset svarklient.

5.5. Endepunkt for tilpasset omdirigering

Dette er endepunktet å omdirigere til etter autentisering med den eksterne leverandøren.

La oss se hvordan vi kan endre baseUri for omdirigeringens endepunkt:

.oauth2Login () .redirectionEndpoint () .baseUri ("/ oauth2 / redirect")

Standard URI er pålogging / oauth2 / kode.

Merk at hvis vi endrer det, må vi også oppdatere redirectUriTemplate eiendom til hver ClientRegistration og legg til den nye URI som en autorisert omdirigerings-URI for hver klient.

5.6. Endepunkt for tilpasset brukerinformasjon

Endepunktet for brukerinfo er stedet vi kan utnytte for å få brukerinformasjon.

Vi kan tilpasse dette endepunktet ved hjelp av userInfoEndpoint () metode. For dette kan vi bruke metoder som userService () og customUserType () for å endre måten brukerinformasjon blir hentet på.

6. Få tilgang til brukerinformasjon

En vanlig oppgave vi kanskje vil oppnå, er å finne informasjon om den påloggede brukeren. For dette, vi kan gjøre en forespørsel til sluttinformasjonen for brukerinformasjonen.

Først må vi få klienten som tilsvarer gjeldende brukertoken:

@Autowired privat OAuth2AuthorizedClientService autorisertClientService; @GetMapping ("/ loginSuccess") offentlig streng getLoginInfo (modellmodell, OAuth2AuthenticationToken-autentisering) {OAuth2AuthorizedClient-klient = autorisertClientService .loadAuthorizedClient (authentication.getAuthorizedClientRegistrationId (), authentication.getName ()); // ... return "loginSuccess"; }

Deretter sender vi en forespørsel til klientens sluttinformasjon for brukerinfo og henter userAttributes Map:

String userInfoEndpointUri = client.getClientRegistration () .getProviderDetails (). GetUserInfoEndpoint (). GetUri (); hvis (! StringUtils.isEmpty (userInfoEndpointUri)) {RestTemplate restTemplate = ny RestTemplate (); HttpHeaders headers = nye HttpHeaders (); headers.add (HttpHeaders.AUTHORIZATION, "Bearer" + client.getAccessToken () .getTokenValue ()); HttpEntity entity = new HttpEntity ("", headers); ResponseEntity response = restTemplate .exchange (userInfoEndpointUri, HttpMethod.GET, entity, Map.class); Kart brukerAttributter = respons.getBody (); model.addAttribute ("navn", userAttributes.get ("navn")); }

Ved å legge til Navn eiendom som en Modell attributt, kan vi vise det i loginSuccess se som velkomstmelding til brukeren:

Ved siden av Navn, de userAttributes Map inneholder også egenskaper som e-post, familienavn,bilde, sted.

7. Konklusjon

I denne artikkelen har vi sett hvordan vi kan bruke oauth2Login () element i Spring Security for å autentisere med forskjellige leverandører som Google og Facebook. Vi har også gått gjennom noen vanlige scenarier for å tilpasse denne prosessen.

Den fulle kildekoden til eksemplene finner du på GitHub.


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