<!-- spring에서 redis에 대한 의존성 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring에서 redis를 session storage로 사용하기 위한 의존성 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
spring
session:
storage-type: redis
redis:
host: localhost
port: 6379
@ConfigurationProperties
사용 (오타 방지, 코드 깔끔하게 사용하기 위함)@Component
@ConfigurationProperties(prefix = "spring.redis")
@Getter
@Setter
public class RedisProperties {
private String host;
private int port;
}
@Configuration
@RequiredArgsConstructor
public class RedisConfigure {
private final RedisProperties redisProperties;
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(redisProperties.getHost());
configuration.setPort(redisProperties.getPort());
return new LettuceConnectionFactory(configuration);
}
}
@EnableRedisHttpSession
추가❗ 주의할 점 : redis는 hash를 사용하기 때문에 사용할 객체(dto)를 직렬화 해줄 필요가 있다. implements Serializable
을 추가해준다.
여기까지가 기본적인 Redis 설정이고 저번에 멘토가 서버를 두 대로 scale-out 했다고 가정하고 진행해보자 했을 때 적용해봤던 내용들이다. 똑같은 어플리케이션 8080, 8081, 8082로 돌려 확인했을 때도 잘 작동했고, 배포 중에도 로그인이 풀리지 않는 것도 확인하여 잘 동작하고 있다는 것을 알 수 있었다.
하지만 이번에 무엇을 잘못했는지 생각처럼 잘 진행되지 않았지만 😂
저번에 API 나눌 떄도 막막했지만 해결하고 나서 많이 배운 것처럼 이번에도 그러리라 믿고 해결하면서 얻은 내용들을 정리해보고자 한다.
이렇게 작업 순 포트 번호를 임시 지정해서 사용하고 있다.
(어차피 dev 환경과 real 환경에 도메인 설정해서 배포하기 때문에 사실 포트 번호는 내 편한대로 설정해도 상관없음)
8083 zuul 서버로 요청을 받고 각 서버스 별로 호출하는 것은 완료를 했지만, 로그인을 성공하고 넘어가도 로그인이 되지않는 상황이 발생했다. (세션 정보가 공유가 안되는 듯) ---> 문제점
이렇게 하면 당연히 될 줄 알았으나.. 실패.
session 확인하는 코드를 작성해서 호출해보니 정상적으로 설정은 된 것 같다.
(개발자 도구에서 확인하는 방법도 있는 듯)
원래 배포하는 서버에 redis 설치하고 사용 중이었는데 답답해서 확인해보려고 local에 설치해서 확인.
user -> 제대로 저장은 되는 것을 확인할 수 있었다.
진짜 안 본 것 없이 다 찾아봐도 그냥 다들 스무스하게 해결한 글 밖에 없어서.. 며칠을 고민하다가 멘토에게 도움을 요청했다. 여기까지 지금 동작하고 어디가 문제인 것 같다 설명해주니 개발자 도구부터 확인해서 쿠키 문제인 것 같다고 조언을 해줬고
https://stackoverflow.com/questions/43625298/spring-session-sharing-between-zuul-and-resource-servers
스택오버플로우에 비슷한 글이 있어 적용해보아도 해결이 안되어서 일단 패스.
그냥 8080에서 로그인해도 8082에서도 세션 정보가 남아있어야 한다고 생각해서 시도해봤는데 계속 classNotFoundException
과 직렬화에 관련된 에러가 자꾸 발생했다. 계속 에러도 내보고 잘 읽다보니 8080에서 set해준 User와 8002에 있는 User는 다른 클래스기 때문에 자꾸 에러가 발생하는 것 같았다. 사실 로그인되면 아이디만 필요하기 때문에 간단하게 User 객체를 set하지 않고 String인 Id만 set해주는 것으로 코드를 교체했고, 해결했다.
--> zuul 서버 이용하지 않으면 세션 공유에 문제가 없다는 것을 확인함.
3번까지 해결하고 나서 이제 쿠키 문제인 것 같다고 해준 조언이 생각나서 다시 한번 들어가서 읽어보니
Redis에 세션을 저장해도, session Id는 쿠키에 저장되며 리소스 서버에 전달되어야 한다고 한다. 그때 멘토와 개발자 도구를 확인했을 때 어쩐지 쿠키가 제대로 전달되지 않는 모습이었는데..
zuul의 디폴트 설정은 헤더와 관련된 모든 쿠키들을 필터링한다고 되어있었다. 👉 여기가 문제였음 !
그래서 마지막 문단에 리소스 서버에 쿠키 관련 헤더를 전달하려면 쿠키 관련 헤더 없이 재정의 해야 한다고 한다.
zuul:
sensitiveHeaders: Authorization
routes:
이런 식으로 재정의 해주었고 문제가 해결되었다. ⭐⭐⭐
https://stackoverflow.com/questions/43625298/spring-session-sharing-between-zuul-and-resource-servers
https://velog.io/@albaneo0724/Spring-Redis%EB%A5%BC-session-storage%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0