이중화된 시스템 Redis를 통한 spring security session관리
1. 개요
Spring Session 은 서버에 저장된 HTTP 세션의 한계로부터 세션 관리를 자유롭게하는 간단한 목표를 가지고 있습니다. Spring sesion을 이용하면 이중화된 시스템에서 분리 된 서버에 환경을 생각없이 하나의 서버에서 사용하는것처럼 사용할 수 있습니다.
이 방법 사용하면 단일 컨테이너 (예 : 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.2.6.RELEASE</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>
우리의 응용 프로그램은 스프링 부트로 실행되며 부모 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. 스프링 부트 설정
먼저 Boot로 Spring Session 을 구성하는 방법을 보여 드리겠습니다 .
참고 : 섹션 3과 4를 완료 할 필요는 없습니다. 스프링 부트 를 사용하여 스프링 세션 을 구성 하는지 여부에 따라 하나만 선택하십시오 .
3.1. Redis 세션 관련 의존성 추가
이 종속성을 프로젝트에 추가하십시오.
<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 에서 찾을 수 있습니다 .
3.2. 스프링 세션 구성
이제 Spring Session에 대한 설정 클래스를 추가하자 :
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
}
4. 표준 스프링 구성 (부트버전이 아닌 버전에서)
스프링 부트없이 스프링 스프링을 통합하고 구성하는 방법에 대해서도 살펴 보자 .
4.1. 의존성
먼저 표준 스프링 프로젝트에 스프링 세션 을 추가 하려면 다음을 명시 적으로 정의해야합니다.
<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 Session에 대한 설정 클래스를 추가하자 :
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
@Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
}
차이점을 최소화 할 수 있습니다. 이제 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(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. 테스트
마지막으로 모든 것을 테스트 해 봅시다. 여기서 두 가지 작업을 수행 할 수있는 간단한 테스트를 정의하겠습니다.
- 라이브 웹 응용 프로그램을 소비
- 레디 스와 대화
먼저 설정을 해보자.
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());
}
이제 보안이 인증되지 않은 요청에 대해 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. 결론
스프링 세션 은 HTTP 세션 관리를위한 강력한 도구입니다. 세션 스토리지를 구성 클래스와 몇 가지 Maven 종속성으로 단순화하여 이제 여러 애플리케이션을 동일한 Redis 인스턴스에 연결하고 인증 정보를 공유 할 수 있습니다.
언제나 그렇듯이 Github 에서 소스 코드 를 찾을 수 있습니다 .
참고
'Spring' 카테고리의 다른 글
RestTemplate에서 List 다루기 (0) | 2020.06.14 |
---|---|
RestTemaplte 사용방법 (0) | 2020.06.13 |
Spring 에서Global Error, Exception handling하는 방법 (0) | 2020.06.12 |
모든 jackson 어노테이션 종류 파악 (1) | 2020.06.11 |
Swagger 를 통한 Spring Rest API 자동화 (0) | 2020.06.10 |