Путеводитель по весенней сессии
1. обзор
Spring Session преследует простую цель - освободить управление сеансом от ограничений сеанса HTTP, хранящегося на сервере.
Решение позволяет легко обмениваться данными сеанса между службами в облаке без привязки к одному контейнеру (т.е. Кот). Кроме того, он поддерживает несколько сеансов в одном браузере и отправку сеансов в заголовке.
В этой статье мы будем использоватьSpring Session для управления данными аутентификации в веб-приложении. ХотяSpring Session может сохранять данные с помощью JDBC, Gemfire или MongoDB, мы будем использоватьRedis.
Чтобы познакомиться сRedis, ознакомьтесь со статьейthis.
2. Простой проект
Давайте сначала создадим простой проектSpring Boot, который позже будет использоваться в качестве основы для наших примеров сеансов:
org.springframework.boot
spring-boot-starter-parent
1.4.0.RELEASE
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
Наше приложение работает сSpring Boot, а родительский pom предоставляет версии для каждой записи. Последнюю версию каждой зависимости можно найти здесь:spring-boot-starter-security,spring-boot-starter-web,spring-boot-starter-test.
Давайте также добавим некоторые свойства конфигурации для нашего сервера Redis вapplication.properties:
spring.redis.host=localhost
spring.redis.port=6379
3. Конфигурация Spring Boot
Во-первых, давайте продемонстрируем настройкуSpring Session с загрузкой.
Примечание: вам не нужно заполнять разделы 3 и 4. Просто выберите один в зависимости от того, используете ли выSpring Boot для настройкиSpring Session.
3.1. зависимости
Добавьте эти зависимости в наш проект:
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.session
spring-session
Мы используем загрузочный родительский pom для установки версий здесь, поэтому они гарантированно будут работать с другими нашими зависимостями. Последнюю версию каждой зависимости можно найти здесь:spring-boot-starter-data-redis,spring-session.
3.2. Конфигурация весенней сессии
Теперь давайте добавим класс конфигурации дляSpring Session:
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
}
4. Стандартная конфигурация Spring (без загрузки)
Давайте также посмотрим на интеграцию и настройкуspring-session без Spring Boot - только с помощью простого Spring.
4.1. зависимости
Во-первых, если мы добавляемspring-session в стандартный проект Spring, нам нужно будет явно определить:
org.springframework.session
spring-session
1.2.2.RELEASE
org.springframework.data
spring-data-redis
1.5.0.RELEASE
Последние версии этих модулей можно найти здесь:spring-session,spring-data-redis
4.2. Конфигурация весенней сессии
Теперь давайте добавим класс конфигурации дляSpring Session:
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
}
Как видите, различия минимальны - нам просто нужно явно определить наш bean-компонентJedisConnectionFactory - Boot сделает это за нас.
В обоих типах@EnableRedisHttpSession и расширениеAbstractHttpSessionApplicationInitializer создаст и подключит фильтр перед всей нашей инфраструктурой безопасности для поиска активных сеансов и заполнения контекста безопасности из значений, хранящихся вRedis .
Теперь давайте дополним это приложение контроллером и конфигурацией безопасности.
5. Конфигурация приложения
Перейдите к нашему основному файлу приложения и добавьте контроллер:
@RestController
public class SessionController {
@RequestMapping("/")
public String helloAdmin() {
return "hello admin";
}
}
Это даст нам конечную точку для тестирования.
Затем добавьте наш класс конфигурации безопасности:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("password").roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/").hasRole("ADMIN")
.anyRequest().authenticated();
}
}
Это защищает наши конечные точки с помощью базовой аутентификации и настраивает пользователя для тестирования.
6. Test
Наконец, давайте все протестируем - здесь мы определим простой тест, который позволит нам сделать 2 вещи:
-
использовать живое веб-приложение
-
поговорить с Redis
Давайте сначала настроим вещи:
public class SessionControllerTest {
private Jedis jedis;
private TestRestTemplate testRestTemplate;
private TestRestTemplate testRestTemplateWithAuth;
private String testUrl = "http://localhost:8080/";
@Before
public void clearRedisData() {
testRestTemplate = new TestRestTemplate();
testRestTemplateWithAuth = new TestRestTemplate("admin", "password", null);
jedis = new Jedis("localhost", 6379);
jedis.flushAll();
}
}
Обратите внимание, как мы настраиваем оба этих клиента - HTTP-клиент и Redis. Конечно, на этом этапе сервер (и Redis) должны быть в рабочем состоянии - чтобы мы могли общаться с ними с помощью этих тестов.
Начнем с проверки, чтоRedis пуст:
@Test
public void testRedisIsEmpty() {
Set result = jedis.keys("*");
assertEquals(0, result.size());
}
Теперь проверьте, что наша система безопасности возвращает 401 для неаутентифицированных запросов:
@Test
public void testUnauthenticatedCantAccess() {
ResponseEntity result = testRestTemplate.getForEntity(testUrl, String.class);
assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
}
Затем мы проверяем, чтоSpring Session управляет нашим токеном аутентификации:
@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
}
Во-первых, наш тест подтверждает, что наш запрос был успешно выполнен с использованием учетных данных администратора.
Затем мы извлекаем значение сеанса из заголовков ответа и используем его в качестве нашей аутентификации во втором запросе. Мы проверяем это, а затем очищаем все данные вRedis.
Наконец, мы делаем еще один запрос, используя cookie-файл сессии, и подтверждаем, что мы вышли из системы. Это подтверждает, чтоSpring Session управляет нашими сеансами.
7. Заключение
Spring Session - мощный инструмент для управления сеансами HTTP. С нашим хранилищем сеансов, упрощенным до класса конфигурации и нескольких зависимостей Maven, теперь мы можем подключить несколько приложений к одному и тому же экземпляруRedis и поделиться информацией аутентификации.
Как всегда, вы можете найти исходный кодover on Github.