1. 개요
Spring Session 은 서버에 저장된 HTTP 세션의 한계에서 세션 관리를 해방시키는 단순한 목표를 가지고 있습니다.
이 솔루션을 사용하면 단일 컨테이너 (예 : Tomcat)에 연결하지 않고도 클라우드의 서비스간에 세션 데이터를 쉽게 공유 할 수 있습니다. 또한 동일한 브라우저에서 여러 세션을 지원하고 헤더로 세션을 전송합니다.
이 기사에서는 Spring Session 을 사용하여 웹 앱에서 인증 정보를 관리합니다. Spring Session 은 JDBC, Gemfire 또는 MongoDB를 사용하여 데이터를 유지할 수 있지만 Redis 를 사용할 것 입니다.
Redis에 대한 소개는 이 기사를 확인 하십시오.
2. 간단한 프로젝트
나중에 세션 예제의 기반으로 사용할 간단한 Spring Boot 프로젝트를 먼저 만들어 보겠습니다 .
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
우리의 애플리케이션은 Spring Boot로 실행되고 부모 pom은 각 항목에 대한 버전을 제공합니다. 각 의존성의 최신 버전은 spring-boot-starter-security , spring-boot-starter-web , spring-boot-starter-test에서 찾을 수 있습니다.
application.properties에 Redis 서버에 대한 몇 가지 구성 속성을 추가해 보겠습니다 .
spring.redis.host=localhost
spring.redis.port=6379
3. 스프링 부트 설정
Spring Boot 의 경우 다음 의존성을 추가하는 것으로 충분 하며 자동 구성이 나머지를 처리합니다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
여기서 버전을 설정하기 위해 부트 부모 pom 을 사용하고 있으므로 다른 의존성과 함께 작동하도록 보장됩니다. 각 의존성의 최신 버전은 spring-boot-starter-data-redis , spring-session 에서 찾을 수 있습니다 .
4. 표준 스프링 구성 (부팅 없음)
또한 Spring Boot없이 Spring 세션 을 통합하고 구성하는 방법을 살펴 보겠습니다 .
4.1. 의존성
먼저 표준 Spring 프로젝트에 spring-session 을 추가하는 경우 명시 적으로 정의해야합니다.
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.5.0.RELEASE</version>
</dependency>
이 모듈의 최신 버전은 spring-session , spring-data-redis 에서 찾을 수 있습니다 .
4.2. Spring 세션 구성
이제 Spring Session에 대한 구성 클래스를 추가해 보겠습니다 .
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
}
@EnableRedisHttpSession 및 AbstractHttpSessionApplicationInitializer 의 확장은 모든 Security 인프라 앞에 필터를 만들고 연결하여 활성 세션을 찾고 Redis에 저장된 값에서 Security 컨텍스트를 채 웁니다 .
이제 컨트롤러와 Security 구성을 사용하여이 애플리케이션을 완료 해 보겠습니다.
5. 애플리케이션 구성
메인 애플리케이션 파일로 이동하여 컨트롤러를 추가합니다.
@RestController
public class SessionController {
@RequestMapping("/")
public String helloAdmin() {
return "hello admin";
}
}
이를 통해 테스트 할 엔드 포인트가 제공됩니다.
다음으로 Security 구성 클래스를 추가합니다.
@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();
}
}
이는 기본 인증으로 엔드 포인트를 보호하고 테스트 할 사용자를 설정합니다.
6. 테스트
마지막으로 모든 것을 테스트 해 보겠습니다. 여기에서 두 가지 작업을 수행 할 수있는 간단한 테스트를 정의하겠습니다.
- 라이브 웹 애플리케이션 사용
- 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<String> result = jedis.keys("*");
assertEquals(0, result.size());
}
이제 Security이 인증되지 않은 요청에 대해 401을 반환하는지 테스트합니다.
@Test
public void testUnauthenticatedCantAccess() {
ResponseEntity<String> result = testRestTemplate.getForEntity(testUrl, String.class);
assertEquals(HttpStatus.UNAUTHORIZED, result.getStatusCode());
}
다음으로 Spring Session 이 인증 토큰을 관리하고 있는지 테스트합니다 .
@Test
public void testRedisControlsSession() {
ResponseEntity<String> result = testRestTemplateWithAuth.getForEntity(testUrl, String.class);
assertEquals("hello admin", result.getBody()); //login worked
Set<String> 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<String> 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의 모든 데이터를 지 웁니다 .
마지막으로 세션 쿠키를 사용하여 또 다른 요청을하고 로그 아웃되었는지 확인합니다. 이것은 Spring Session 이 우리 세션을 관리하고 있음을 확인 합니다.
7. 결론
Spring Session 은 HTTP 세션을 관리하기위한 강력한 도구입니다. 세션 저장소를 구성 클래스로 단순화하고 Maven 의존성을 몇 개 사용하여 이제 여러 애플리케이션을 동일한 Redis 인스턴스에 연결하고 인증 정보를 공유 할 수 있습니다.
항상 그렇듯이 모든 예제는 Github에서 사용할 수 있습니다 .