Simple Single Sign-On dengan Spring Security OAuth2 (tumpukan lama)

1. Ikhtisar

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

Kami akan menggunakan tiga aplikasi terpisah:

  • Server Otorisasi - yang merupakan mekanisme otentikasi pusat
  • Dua Aplikasi Klien: aplikasi yang menggunakan SSO

Sederhananya, ketika pengguna mencoba mengakses halaman yang diamankan di aplikasi klien, mereka akan dialihkan untuk mengautentikasi terlebih dahulu, melalui Server Otentikasi.

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

Catatan : artikel ini menggunakan proyek lama Spring OAuth. Untuk versi artikel ini yang menggunakan tumpukan Spring Security 5 yang baru, lihat artikel kami Simple Single Sign-On dengan Spring Security OAuth2.

2. Aplikasi Klien

Mari kita mulai dengan Aplikasi Klien kami; kami, tentu saja, akan menggunakan Spring Boot untuk meminimalkan konfigurasi:

2.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-security   org.springframework.security.oauth.boot spring-security-oauth2-autoconfigure 2.0.1.RELEASE   org.springframework.boot spring-boot-starter-thymeleaf   org.thymeleaf.extras thymeleaf-extras-springsecurity4 

2.2. Konfigurasi Keamanan

Selanjutnya, bagian terpenting, konfigurasi keamanan aplikasi klien kami:

@Configuration @EnableOAuth2Sso public class UiSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.antMatcher("/**") .authorizeRequests() .antMatchers("/", "/login**") .permitAll() .anyRequest() .authenticated(); } }

Bagian inti dari konfigurasi ini, tentu saja, anotasi @ EnableOAuth2Sso yang kami gunakan untuk mengaktifkan Sistem Masuk Tunggal.

Perhatikan bahwa kita perlu memperluas WebSecurityConfigurerAdapter - tanpanya, semua jalur akan diamankan - sehingga pengguna akan dialihkan untuk masuk saat mereka mencoba mengakses halaman mana pun. Dalam kasus kami di sini, halaman indeks dan login adalah satu-satunya halaman yang dapat diakses tanpa otentikasi.

Akhirnya, kami juga mendefinisikan kacang RequestContextListener untuk menangani cakupan permintaan.

Dan application.yml :

server: port: 8082 servlet: context-path: /ui session: cookie: name: UISESSION security: basic: enabled: false oauth2: client: clientId: SampleClientId clientSecret: secret accessTokenUri: //localhost:8081/auth/oauth/token userAuthorizationUri: //localhost:8081/auth/oauth/authorize resource: userInfoUri: //localhost:8081/auth/user/me spring: thymeleaf: cache: false

Beberapa catatan singkat:

  • kami menonaktifkan Autentikasi Dasar default
  • accessTokenUri adalah URI untuk mendapatkan Token Akses
  • userAuthorizationUri adalah URI otorisasi tempat pengguna akan dialihkan
  • userInfoUri URI titik akhir pengguna untuk mendapatkan detail pengguna saat ini

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.

2.3. 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 :

 Login

Dan securePage.html :

 Welcome, Name

The securedPage.html halaman yang dibutuhkan pengguna untuk disahkan. Jika pengguna yang tidak diautentikasi mencoba mengakses securePage.html , mereka akan dialihkan ke halaman login terlebih dahulu.

3. Server Auth

Sekarang mari kita bahas Server Otorisasi kita di sini.

3.1. Dependensi Maven

Pertama, kita perlu mendefinisikan dependensi di pom.xml kita :

 org.springframework.boot spring-boot-starter-web   org.springframework.security.oauth spring-security-oauth2 2.3.3.RELEASE 

3.2. Konfigurasi OAuth

Penting untuk dipahami bahwa kita akan menjalankan Server Otorisasi dan Server Sumber Daya bersama-sama di sini, sebagai satu unit yang dapat diterapkan.

Mari kita mulai dengan konfigurasi Server Sumber Daya kita - yang juga berfungsi sebagai aplikasi Boot utama kita:

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

Kemudian, kami akan mengonfigurasi server Otorisasi kami:

@Configuration @EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private BCryptPasswordEncoder passwordEncoder; @Override public void configure( AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("SampleClientId") .secret(passwordEncoder.encode("secret")) .authorizedGrantTypes("authorization_code") .scopes("user_info") .autoApprove(true) .redirectUris( "//localhost:8082/ui/login","//localhost:8083/ui2/login"); } }

Perhatikan bagaimana kami hanya mengaktifkan klien sederhana menggunakan jenis pemberian authorization_code .

Selain itu, perhatikan bagaimana autoApprove disetel ke true sehingga kita tidak dialihkan dan dipromosikan untuk menyetujui cakupan apa pun secara manual.

3.3. Konfigurasi Keamanan

Pertama, kami akan menonaktifkan Autentikasi Dasar default, melalui application.properties kami :

server.port=8081 server.servlet.context-path=/auth

Sekarang, mari pindah ke konfigurasi dan tentukan mekanisme login formulir sederhana:

@Configuration @Order(1) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.requestMatchers() .antMatchers("/login", "/oauth/authorize") .and() .authorizeRequests() .anyRequest().authenticated() .and() .formLogin().permitAll(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("john") .password(passwordEncoder().encode("123")) .roles("USER"); } @Bean public BCryptPasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }

Perhatikan bahwa kami menggunakan otentikasi dalam memori sederhana, tetapi kami dapat menggantinya dengan custom userDetailsService .

3.4. Titik Akhir Pengguna

Terakhir, kami akan membuat titik akhir pengguna yang kami gunakan sebelumnya dalam konfigurasi kami:

@RestController public class UserController { @GetMapping("/user/me") public Principal user(Principal principal) { return principal; } }

Secara alami, ini akan mengembalikan data pengguna dengan representasi JSON.

4. Kesimpulan

Dalam tutorial singkat ini, kami fokus pada penerapan Single Sign-On menggunakan Spring Security Oauth2 dan Spring Boot.

Seperti biasa, kode sumber lengkap dapat ditemukan di GitHub.