Beberapa Penyedia Otentikasi di Keamanan Musim Semi

1. Ikhtisar

Dalam artikel singkat ini, kami akan fokus pada penggunaan berbagai mekanisme untuk mengautentikasi pengguna di Keamanan Musim Semi.

Kami akan melakukannya dengan mengkonfigurasi beberapa penyedia otentikasi.

2. Penyedia Otentikasi

Sebuah AuthenticationProvider adalah abstraksi untuk mengambil informasi pengguna dari repositori tertentu (seperti database, LDAP, sumber pihak kustom ketiga, dll). Ini menggunakan informasi pengguna yang diambil untuk memvalidasi kredensial yang diberikan.

Sederhananya, ketika beberapa penyedia otentikasi ditentukan, penyedia akan ditanyai sesuai urutan mereka dideklarasikan.

Untuk demonstrasi singkat, kami akan mengonfigurasi dua penyedia otentikasi - penyedia otentikasi khusus dan penyedia otentikasi dalam memori.

3. Ketergantungan Maven

Pertama-tama, tambahkan dependensi Spring Security yang diperlukan ke dalam aplikasi web kita:

 org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-security  

Dan, tanpa Spring Boot:

 org.springframework.security spring-security-web 5.2.2.RELEASE   org.springframework.security spring-security-core 5.2.2.RELEASE   org.springframework.security spring-security-config 5.2.2.RELEASE 

Versi terbaru dari ketergantungan ini dapat ditemukan di spring-security-web, spring-security-core, dan spring-security-config.

4. Penyedia Otentikasi Kustom

Sekarang mari buat penyedia otentikasi khusus dengan mengimplementasikan antarmuka AuthneticationProvider .

Kami akan menerapkan metode otentikasi - yang mencoba otentikasi. Objek Otentikasi input berisi kredensial nama pengguna dan kata sandi yang diberikan oleh pengguna.

The mengotentikasi Metode mengembalikan sepenuhnya dihuni Authentication objek jika otentikasi berhasil. Jika otentikasi gagal, itu memunculkan pengecualian jenis AuthenticationException :

@Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { String username = auth.getName(); String password = auth.getCredentials() .toString(); if ("externaluser".equals(username) && "pass".equals(password)) { return new UsernamePasswordAuthenticationToken (username, password, Collections.emptyList()); } else { throw new BadCredentialsException("External system authentication failed"); } } @Override public boolean supports(Class auth) { return auth.equals(UsernamePasswordAuthenticationToken.class); } }

Secara alami, ini adalah implementasi sederhana untuk tujuan contoh kita di sini.

5. Konfigurasi Beberapa Penyedia Otentikasi

Sekarang mari tambahkan CustomAuthenticationProvider dan penyedia otentikasi dalam memori ke konfigurasi Keamanan Musim Semi kita.

5.1. Konfigurasi Java

Di kelas konfigurasi kita, sekarang mari buat dan tambahkan penyedia otentikasi menggunakan AuthenticationManagerBuilder .

Pertama, CustomAuthenticationProvider dan kemudian, penyedia otentikasi dalam memori dengan menggunakan inMemoryAuthentication () .

Kami juga memastikan bahwa akses ke pola URL " / api / ** " perlu diautentikasi:

@EnableWebSecurity public class MultipleAuthProvidersSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired CustomAuthenticationProvider customAuthProvider; @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(customAuthProvider); auth.inMemoryAuthentication() .withUser("memuser") .password(encoder().encode("pass")) .roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { http.httpBasic() .and() .authorizeRequests() .antMatchers("/api/**") .authenticated(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }

5.2. Konfigurasi XML

Alternatifnya, jika kita ingin menggunakan konfigurasi XML daripada konfigurasi Java:

6. Aplikasi

Selanjutnya, mari buat titik akhir REST sederhana yang diamankan oleh dua penyedia otentikasi kami.

Untuk mengakses titik akhir ini, nama pengguna dan kata sandi yang valid harus diberikan. Penyedia otentikasi kami akan memvalidasi kredensial dan menentukan apakah akan mengizinkan akses atau tidak:

@RestController public class MultipleAuthController { @GetMapping("/api/ping") public String getPing() { return "OK"; } }

7. Pengujian

Terakhir, sekarang mari kita uji akses ke aplikasi aman kita. Akses hanya akan diizinkan jika kredensial yang valid diberikan:

@Autowired private TestRestTemplate restTemplate; @Test public void givenMemUsers_whenGetPingWithValidUser_thenOk() { ResponseEntity result = makeRestCallToGetPing("memuser", "pass"); assertThat(result.getStatusCodeValue()).isEqualTo(200); assertThat(result.getBody()).isEqualTo("OK"); } @Test public void givenExternalUsers_whenGetPingWithValidUser_thenOK() { ResponseEntity result = makeRestCallToGetPing("externaluser", "pass"); assertThat(result.getStatusCodeValue()).isEqualTo(200); assertThat(result.getBody()).isEqualTo("OK"); } @Test public void givenAuthProviders_whenGetPingWithNoCred_then401() { ResponseEntity result = makeRestCallToGetPing(); assertThat(result.getStatusCodeValue()).isEqualTo(401); } @Test public void givenAuthProviders_whenGetPingWithBadCred_then401() { ResponseEntity result = makeRestCallToGetPing("user", "bad_password"); assertThat(result.getStatusCodeValue()).isEqualTo(401); } private ResponseEntity makeRestCallToGetPing(String username, String password) { return restTemplate.withBasicAuth(username, password) .getForEntity("/api/ping", String.class, Collections.emptyMap()); } private ResponseEntity makeRestCallToGetPing() { return restTemplate .getForEntity("/api/ping", String.class, Collections.emptyMap()); }

8. Kesimpulan

Dalam tutorial singkat ini, kita telah melihat bagaimana beberapa penyedia otentikasi dapat dikonfigurasi di Keamanan Musim Semi. Kami telah mengamankan aplikasi sederhana menggunakan penyedia otentikasi khusus dan penyedia otentikasi dalam memori.

Dan kami juga telah menulis tes untuk memverifikasi bahwa akses ke aplikasi kami memerlukan kredensial yang dapat divalidasi oleh setidaknya salah satu penyedia otentikasi kami.

Seperti biasa, kode sumber lengkap dari implementasi dapat ditemukan di GitHub.