Panduan untuk Sesi Musim Semi

REST Top

Saya baru saja mengumumkan kursus Learn Spring baru , yang berfokus pada dasar-dasar Spring 5 dan Spring Boot 2:

>> LIHAT KURSUSnya

1. Ikhtisar

Sesi Musim Semi memiliki tujuan sederhana untuk membebaskan manajemen sesi dari batasan sesi HTTP yang disimpan di server.

Solusinya memudahkan untuk berbagi data sesi antar layanan di awan tanpa terikat ke satu wadah (yaitu Tomcat). Selain itu, ini mendukung beberapa sesi di browser yang sama dan mengirim sesi di header.

Di artikel ini, kami akan menggunakan Spring Session untuk mengelola informasi autentikasi di aplikasi web. Meskipun Sesi Musim Semi dapat mempertahankan data menggunakan JDBC, Gemfire, atau MongoDB, kami akan menggunakan Redis .

Untuk pengantar Redis, lihat artikel ini.

2. Proyek Sederhana

Mari pertama-tama buat proyek Spring Boot sederhana untuk digunakan sebagai dasar untuk contoh sesi kita nanti:

 org.springframework.boot spring-boot-starter-parent 2.2.6.RELEASE     org.springframework.boot spring-boot-starter-security   org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-test test  

Aplikasi kami berjalan dengan Spring Boot dan pom induk menyediakan versi untuk setiap entri. Versi terbaru setiap dependensi dapat ditemukan di sini: spring-boot-starter-security, spring-boot-starter-web, spring-boot-starter-test.

Mari tambahkan juga beberapa properti konfigurasi untuk server Redis kita di application.properties :

spring.redis.host=localhost spring.redis.port=6379

3. Konfigurasi Spring Boot

Untuk Spring Boot, cukup menambahkan dependensi berikut , dan konfigurasi otomatis akan menangani sisanya:

 org.springframework.boot spring-boot-starter-data-redis   org.springframework.session spring-session-data-redis 

Kami menggunakan boot parent pom untuk menyetel versi di sini, jadi ini dijamin bekerja dengan dependensi kami yang lain. Versi terbaru setiap dependensi dapat ditemukan di sini: spring-boot-starter-data-redis, spring-session.

4. Konfigurasi Musim Semi Standar (tanpa Boot)

Mari kita juga melihat sesi musim semi yang mengintegrasikan dan mengonfigurasi tanpa Spring Boot - hanya dengan Spring biasa.

4.1. Dependensi

Pertama, jika kita menambahkan sesi musim semi ke proyek Musim Semi standar, kita perlu mendefinisikan secara eksplisit:

 org.springframework.session spring-session 1.2.2.RELEASE   org.springframework.data spring-data-redis 1.5.0.RELEASE 

Versi terbaru dari modul ini dapat ditemukan di sini: spring-session, spring-data-redis.

4.2. Konfigurasi Sesi Musim Semi

Sekarang mari tambahkan kelas konfigurasi untuk Sesi Musim Semi :

@Configuration @EnableRedisHttpSession public class SessionConfig extends AbstractHttpSessionApplicationInitializer { @Bean public JedisConnectionFactory connectionFactory() { return new JedisConnectionFactory(); } }

@EnableRedisHttpSession dan ekstensi AbstractHttpSessionApplicationInitializer akan membuat dan memasang filter di depan semua infrastruktur keamanan kami untuk mencari sesi aktif dan mengisi konteks keamanan dari nilai yang disimpan di Redis .

Sekarang mari selesaikan aplikasi ini dengan pengontrol dan konfigurasi keamanan.

5. Konfigurasi Aplikasi

Arahkan ke file aplikasi utama kami dan tambahkan pengontrol:

@RestController public class SessionController { @RequestMapping("/") public String helloAdmin() { return "hello admin"; } }

Ini akan memberi kita titik akhir untuk diuji.

Selanjutnya, tambahkan kelas konfigurasi keamanan kami:

@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("admin") .password(passwordEncoder().encode("password")) .roles("ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { http .httpBasic().and() .authorizeRequests() .antMatchers("/").hasRole("ADMIN") .anyRequest().authenticated(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }

Ini melindungi titik akhir kami dengan otentikasi dasar dan menyiapkan pengguna untuk diuji.

6. Uji

Terakhir, mari kita uji semuanya - kami akan menentukan tes sederhana di sini yang memungkinkan kami melakukan 2 hal:

  • mengkonsumsi aplikasi web langsung
  • berbicara dengan Redis

Mari kita atur dulu:

public class SessionControllerTest { private Jedis jedis; private TestRestTemplate testRestTemplate; private TestRestTemplate testRestTemplateWithAuth; private String testUrl = "//localhost:8080/"; @Before public void clearRedisData() { testRestTemplate = new TestRestTemplate(); testRestTemplateWithAuth = new TestRestTemplate("admin", "password", null); jedis = new Jedis("localhost", 6379); jedis.flushAll(); } }

Perhatikan bagaimana kami menyiapkan kedua klien ini - klien HTTP dan yang Redis. Tentu saja, pada titik ini server (dan Redis) harus aktif dan berjalan - sehingga kami dapat berkomunikasi dengan mereka melalui pengujian ini.

Mari kita mulai dengan menguji apakah Redis kosong:

@Test public void testRedisIsEmpty() { Set result = jedis.keys("*"); assertEquals(0, result.size()); }

Sekarang uji apakah keamanan kami mengembalikan 401 untuk permintaan yang tidak diautentikasi:

@Test public void testUnauthenticatedCantAccess() { ResponseEntity result = testRestTemplate.getForEntity(testUrl, String.class); assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode()); }

Selanjutnya, kami menguji bahwa Spring Session mengelola token autentikasi kami:

@Test public void testRedisControlsSession() { ResponseEntity result = testRestTemplateWithAuth.getForEntity(testUrl, String.class); assertEquals("hello admin", result.getBody()); //login worked Set redisResult = jedis.keys("*"); assertTrue(redisResult.size() > 0); //redis is populated with session data String sessionCookie = result.getHeaders().get("Set-Cookie").get(0).split(";")[0]; HttpHeaders headers = new HttpHeaders(); headers.add("Cookie", sessionCookie); HttpEntity httpEntity = new HttpEntity(headers); result = testRestTemplate.exchange(testUrl, HttpMethod.GET, httpEntity, String.class); assertEquals("hello admin", result.getBody()); //access with session works worked jedis.flushAll(); //clear all keys in redis result = testRestTemplate.exchange(testUrl, HttpMethod.GET, httpEntity, String.class); assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode()); //access denied after sessions are removed in redis }

First, our test confirms that our request was successful using the admin authentication credentials.

Then we extract the session value from the response headers and use it as our authentication in our second request. We validate that, and then clear all the data in Redis.

Finally, we make another request using the session cookie and confirm that we are logged out. This confirms that Spring Session is managing our sessions.

7. Conclusion

Spring Session is a powerful tool for managing HTTP sessions. With our session storage simplified to a configuration class and a few Maven dependencies, we can now wire up multiple applications to the same Redis instance and share authentication information.

Seperti biasa, semua contoh tersedia di Github.

REST bawah

Saya baru saja mengumumkan kursus Learn Spring baru , yang berfokus pada dasar-dasar Spring 5 dan Spring Boot 2:

>> LIHAT KURSUSnya