Simple Single Sign-On dengan Spring Security OAuth2

1. Ikhtisar

Dalam tutorial ini, kita akan membahas cara menerapkan SSO - Sistem Masuk Tunggal - menggunakan Spring Security OAuth dan Spring Boot, menggunakan Keycloak sebagai Server Otorisasi.

Kami akan menggunakan 4 aplikasi terpisah:

  • Server Otorisasi - yang merupakan mekanisme otentikasi pusat
  • A Resource Server - penyedia Foo s
  • Dua Aplikasi Klien - aplikasi yang menggunakan SSO

Sederhananya, ketika pengguna mencoba mengakses sumber daya melalui satu aplikasi Klien, mereka akan dialihkan untuk mengautentikasi terlebih dahulu, melalui Server Otorisasi. Keycloak akan membuat pengguna login, dan saat masih login di aplikasi pertama, jika aplikasi Klien kedua diakses menggunakan browser yang sama, pengguna tidak perlu memasukkan kredensial mereka lagi.

Kami akan menggunakan jenis pemberian Kode Otorisasi dari OAuth2 untuk mendorong delegasi autentikasi.

Kami akan menggunakan tumpukan OAuth di Spring Security 5. Jika Anda ingin menggunakan tumpukan lama OAuth Keamanan Musim Semi, lihat artikel sebelumnya ini: Sistem Masuk Tunggal Sederhana dengan Keamanan Musim Semi OAuth2 (tumpukan lawas)

Sesuai panduan migrasi:

Keamanan Spring merujuk ke fitur ini sebagai OAuth 2.0 Login sedangkan Spring Security OAuth merujuknya sebagai SSO

Baiklah, ayo langsung masuk.

2. Server Otorisasi

Sebelumnya, tumpukan OAuth Keamanan Musim Semi menawarkan kemungkinan untuk menyiapkan Server Otorisasi sebagai Aplikasi Musim Semi.

Namun, tumpukan OAuth sudah tidak digunakan lagi oleh Spring dan sekarang kami akan menggunakan Keycloak sebagai Server Otorisasi kami.

Jadi kali ini, kami akan menyiapkan Server Otorisasi kami sebagai server Keycloak tertanam di aplikasi Spring Boot .

Dalam pra-konfigurasi kami , kami akan menentukan dua klien, ssoClient-1 dan ssoClient-2 , satu untuk setiap Aplikasi Klien.

3. Server Sumber Daya

Selanjutnya, kita membutuhkan Resource Server, atau REST API yang akan memberi kita Foo yang akan digunakan oleh Aplikasi Klien kita.

Ini pada dasarnya sama seperti yang kami gunakan untuk Aplikasi Klien Angular kami sebelumnya.

4. Aplikasi Klien

Sekarang mari kita lihat Aplikasi Klien Thymeleaf; kami, tentu saja, akan menggunakan Spring Boot untuk meminimalkan konfigurasi.

Ingatlah bahwa kami harus memiliki 2 di antaranya untuk mendemonstrasikan fungsi Sistem Masuk Tunggal .

4.1. Dependensi Maven

Pertama, kita membutuhkan dependensi berikut di pom.xml kita :

 org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-oauth2-client   org.springframework.boot spring-boot-starter-thymeleaf   org.thymeleaf.extras thymeleaf-extras-springsecurity5   org.springframework spring-webflux   io.projectreactor.netty reactor-netty 

Untuk menyertakan semua dukungan klien yang kami perlukan, termasuk keamanan, kami hanya perlu menambahkan spring-boot-starter-oauth2-client . Juga, karena RestTemplate lama tidak akan digunakan lagi, kami akan menggunakan WebClient , dan itulah mengapa kami menambahkan spring-webflux dan reactor-netty .

4.2. Konfigurasi Keamanan

Selanjutnya, bagian terpenting, konfigurasi keamanan aplikasi klien pertama kami:

@EnableWebSecurity public class UiSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.antMatcher("/**") .authorizeRequests() .antMatchers("/") .permitAll() .anyRequest() .authenticated() .and() .oauth2Login(); } @Bean WebClient webClient(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) { ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository, authorizedClientRepository); oauth2.setDefaultOAuth2AuthorizedClient(true); return WebClient.builder().apply(oauth2.oauth2Configuration()).build(); } }

Bagian inti dari konfigurasi ini adalah metode oauth2Login () , yang digunakan untuk mengaktifkan dukungan Login OAuth 2.0 dari Spring Security. Karena kami menggunakan Keycloak, yang secara default merupakan solusi sistem masuk tunggal untuk aplikasi web dan layanan web RESTful, kami tidak perlu menambahkan konfigurasi lebih lanjut untuk SSO.

Akhirnya, kami juga mendefinisikan kacang WebClient untuk bertindak sebagai Klien HTTP sederhana untuk menangani permintaan yang akan dikirim ke Server Sumber Daya kami.

Dan inilah application.yml tersebut :

spring: security: oauth2: client: registration: custom: client-id: ssoClient-1 client-secret: ssoClientSecret-1 scope: read,write authorization-grant-type: authorization_code redirect-uri: //localhost:8082/ui-one/login/oauth2/code/custom provider: custom: authorization-uri: //localhost:8083/auth/realms/baeldung/protocol/openid-connect/auth token-uri: //localhost:8083/auth/realms/baeldung/protocol/openid-connect/token user-info-uri: //localhost:8083/auth/realms/baeldung/protocol/openid-connect/userinfo user-name-attribute: preferred_username thymeleaf: cache: false server: port: 8082 servlet: context-path: /ui-one resourceserver: api: project: url: //localhost:8081/sso-resource-server/api/foos/ 

Di sini, spring.security.oauth2.client.registration adalah namespace root untuk mendaftarkan klien. Kami mendefinisikan klien dengan kustom ID pendaftaran . Kemudian kami mendefinisikan client-id , client-secret , scope , authorization-grant-type dan redirect-uri , yang tentu saja, harus sama dengan yang didefinisikan untuk Server Otorisasi kami.

Setelah itu, kami menetapkan penyedia layanan kami atau Server Otorisasi, lagi-lagi dengan id kustom yang sama , dan mencantumkan URI berbeda untuk Spring Security yang akan digunakan. Hanya itu yang perlu kita definisikan, dan framework melakukan seluruh proses masuk, termasuk pengalihan ke Keycloak, dengan mulus bagi kita .

Perhatikan juga bahwa, dalam contoh kami di sini, kami meluncurkan Server Otorisasi kami, tetapi tentu saja kami juga dapat menggunakan penyedia pihak ketiga lainnya seperti Facebook atau GitHub.

4.3. Pengendali

Sekarang mari kita terapkan pengontrol kami di Aplikasi Klien untuk meminta Foo dari Server Sumber Daya kami:

@Controller public class FooClientController { @Value("${resourceserver.api.url}") private String fooApiUrl; @Autowired private WebClient webClient; @GetMapping("/foos") public String getFoos(Model model) { List foos = this.webClient.get() .uri(fooApiUrl) .retrieve() .bodyToMono(new ParameterizedTypeReference
    
     () { }) .block(); model.addAttribute("foos", foos); return "foos"; } }
    

Seperti yang bisa kita lihat, kita hanya memiliki satu metode di sini yang akan membagikan sumber daya ke template foos . Kami tidak perlu menambahkan kode apa pun untuk masuk.

4.4. Paling depan

Sekarang, mari kita lihat konfigurasi front-end aplikasi klien kita. Kami tidak akan fokus pada itu di sini, terutama karena kami sudah membahasnya di situs.

Aplikasi klien kami di sini memiliki front-end yang sangat sederhana; inilah index.html :

Spring OAuth Client Thymeleaf - 1 Welcome !

Login

Dan foos.html :

Spring OAuth Client Thymeleaf -1 Hi, preferred_username   
    
ID Name
No foos
ID Name

The foos.html halaman membutuhkan pengguna untuk disahkan. Jika pengguna yang tidak diautentikasi mencoba mengakses foos.html , mereka akan dialihkan ke halaman login Keycloak terlebih dahulu .

4.5. Aplikasi Klien Kedua

We'll configure a second application, Spring OAuth Client Thymeleaf -2 using another client_idssoClient-2.

It'll mostly be the same as the first application we just described.

The application.yml will differ to include a different client_id, client_secret and redirect_uri in its spring.security.oauth2.client.registration:

spring: security: oauth2: client: registration: custom: client-id: ssoClient-2 client-secret: ssoClientSecret-2 scope: read,write authorization-grant-type: authorization_code redirect-uri: //localhost:8084/ui-two/login/oauth2/code/custom

And, of course, we need to have a different server port for it as well, so that we can run them in parallel:

server: port: 8084 servlet: context-path: /ui-two

Finally, we'll tweak the front end HTMLs to have a title as Spring OAuth Client Thymeleaf – 2 instead of – 1 so that we can distinguish between the two.

5. Testing SSO Behavior

To test SSO behavior, let's run our Applications.

We'll need all our 4 Boot Apps – the Authorization Server, the Resource Server and both Client Applications – to be up and running for this.

Now let's open up a browser, say Chrome, and log in to Client-1 using the credentials [email protected]/123. Next, in another window or tab, hit the URL for Client-2. On clicking the login button, we'll be redirected to the Foos page straightaway, bypassing the authentication step.

Similarly, if the user logs in to Client-2 first, they need not enter their username/password for Client-1.

6. Conclusion

Dalam tutorial ini, kami fokus pada penerapan Single Sign-On menggunakan Spring Security OAuth2 dan Spring Boot menggunakan Keycloak sebagai penyedia identitas.

Seperti biasa, kode sumber lengkap dapat ditemukan di GitHub.