Spring

이중화된 시스템 Redis를 통한 Spring security session관리

기록만이살길 2020. 6. 13. 15:16
반응형

이중화된 시스템 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 가이 를 대신합니다.

@EnableRedisHttpSessionAbstractHttpSessionApplicationInitializer 의 확장은 두 유형 모두 에서 모든 보안 인프라 앞에 필터를 생성하고 연결하여 활성 세션을 찾고 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 에서 소스 코드 찾을 수 있습니다 .

참고

https://www.baeldung.com/spring-session

반응형