본문 바로가기
Spring

[Spring]Redis + SpringBoot : 레디스 연동하기 (gradle, yml)

by windy7271 2024. 2. 2.
728x90
반응형

스프링부트 2.7.x  , gradle

java 11

 

기본 게시판을 만들던 중

세션을 레디스에 띄어 놓기 위해서. 레디스와 스프링부트를 연결해 세션정보를 레디스에서 관리하도록 해보겠습니다.

 

레디스는 도커 를 사용 해보겠습니다.

 

 

1. docker ps 

- 현재 가동중인 도커를 보여줍니다. 레디스가 없으면

2. docker run -d -p 6379:6379 redis 

- 레디스를 받아주시구요

3. 다시 docker ps

- 레디스에 containerID 가나옵니다.

4. 레디스 실행

docker exec -it f8bccab9b30c /bin/sh  를 해주면

# 으로 바뀌어야 합니다.

 

 

 

도커를 확인해보면 이렇게 레디스가 돌아가고 있습니다. 포트는 6379 이고요

 

이제 스프링과 이어보도록하겠습니다.

 

 

0. build.gradle추가, @EnableRedisHttpSession 추가

//  session 스토리지를 redis에 저장하기 위한 패키지
   implementation 'org.springframework.session:spring-session-data-redis'

 

@EnableRedisHttpSession // 세션 스토리지를 Redis로 사용하겠다라는 설정
public class BoardApplication {

   public static void main(String[] args) {
      SpringApplication.run(BoardApplication.class, args);
   }

}

 

 

1. application.yml 에 

spring 아랫단에 추가해줍니다. 

spring:
  session:
    storage-type: redis
  redis:
    host: localhost
    port: 6379

 

 

저는 세션을 사용 했기 때문에 로그인이 성공시에 세션을 저장해야합니다.

 

2. LoginSuccessHandler

public class LoginSuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        HttpSession httpSession = request.getSession();
//        authentication 안에는 User객체가 들어가 있고, 여기서 getName은 email 을 의미한다.
        httpSession.setAttribute("email", authentication.getName());
        response.sendRedirect("/");
    }
}

 

2.RedisConfig

@Configuration
public class RedisConfig {
    //    yml 안에 있는 정보를 프로그램 안으로 가져온다.
    @Value("${spring.redis.host}")
    public String host;
    @Value("${spring.redis.port}")
    public int port;


    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        return new LettuceConnectionFactory(redisStandaloneConfiguration);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
}

 

레디스를 사용하기 위한 Redis 연결 설정과

RedisTemplate를 성정하는 두 개 의 메서드가 있습니다. 간단하게 설명을 해보겠습니다.

 

RedicConnectionFactory 는 Redis와 서버와의 연결을 설정하고 제공하는 인터페이스입니다

객체를 생성하여 포트와 호스트를 설정한 후 빈을 생성하여 스프링 컨테이너에 저장합니다.

 

두 번째 메소드는 Redis의 저장되는 키와 값을 JSON직렬화 방식으로 설정하는 것입니다.

 

 

3. LoginService

Service
public class LoginService  implements UserDetailsService {

    private final AuthorService authorService;

    public LoginService(AuthorService authorService) {
        this.authorService = authorService;
    }

//    내부적으로 로그인시 유저의 정보를 세션에 저장하기 위해 필요한 코드.
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            Author author = authorService.findByEmail(username);
    //        매개변수 : userEmail, password, 권한(authorities)

    //        권한이 여러개있을수도 있어서 []
            List<GrantedAuthority> authorities = new ArrayList<>();
    //        Role_권한 패턴으로 스프링에서 기본적으로 권한 체크 ex)ROLE_ADMIN
            authorities.add(new SimpleGrantedAuthority("ROLE_"+author.getRole()));
    //       해당 메서드에서 return 되는 User객체는 Session 메모리에 저장소에 저장되어, 계속 사용 가능
            return new User(author.getEmail(), author.getPassword(),authorities);
        }
}

 

로그인 성공시 User객체 생성 하기 위한 코드입니다.

User객체안에는 이메일,비밀번호,권한(리스트) 로 저장합니다.

"ROLE_ " 를 추가해주는 의미는 스프링은 자체적으로 ROLE_ 을 붙여서 이해하기 떄문입니다. 그래서 저걸 붙여줘야

ROLE_ADMIN 이렇게 됩니다.

 

로그인 페이지 

<div class="container">
  <div class="page-header">
    <h1>로그인</h1>
  </div>
  <div id="update-form" class="mt-4">

    <form action="/doLogin" method="POST">
      <div class="form-group">
        <label for="email">email: </label>
        <input name="email" class="form-control" type="text" id="email">
      </div>

      <div class="form-group">
        <label for="password">비번: </label>
        <input name="pw" class="form-control" type="password" id="password">
      </div>

      <button class="btn btn-primary" type="submit" value="로그인">로그인</button>
    </form>
  </div>
</div>

 

로그인 절차와 검증은 다음과 같습니다.

1. id/pw 를 입력하여 로그인 시도

여기서는 ( email , pw )

저걸로 doLogin을 호출하면 스프링 내부적인 메서드(doLogin) 으로 로그인 시도합니다

.loginProcessingUrl("/doLogin")
.usernameParameter("email")
.passwordParameter("pw")
.successHandler(new LoginSuccessHandler())

 

 

2. LoginService 에서 loadUserByUsername에서 db를 조회한 User객체 생성합니다.

3. 로그인 성공시 Authentication객체에 사용자정보(email, role등)을 담고, 사용자에게 SESSIONID를 전달합니다.

 

{JSESSIONID=7D93988F492D21A0D5FC24E37AFFE56A : USER(email,password,Role)}

로그인 성공시 :

  1. 키값 발급 → 사용자 정보를 메모리에 저장 (Authentication, 세션저장소) 사용자에게 키값을 전달
  2. 사용자 정보를 메모리에 저장 (세션저장소)

회원 조회, 게시글 조회 → 쿠키(세션 id) 를 서버에 request값으로 함께 전달

 

 

 

이제 한번 해볼까요? 

그냥 레디스에서 키를 뽑아볼게요

 

 

키가 없습니다. 로그인을 안 했거든요 

3번님 환영합니다 !

 

레디스에 들어왔는지 확인해볼까요 ?

 

 

너무 많아요.. 

여러 정보가 들어있나봐요

 

로그아웃하니 2개가 날라가네요. 확인 해 보니 시간이 지나면 사라집니다.

 

 

 

 

cf) 

세션방식 vs 토큰방식

가장 큰 차이점 :

  • 세션은 프로그램이 꺼지기 전에 세션 스토리지(메모리) 어디에 저장한다.
  • 토큰은 사용자의 인증정보를 저장을 안한다.

곧 토큰 버전도 커스텀해서 가져오도록 하겠습니다.

반응형

댓글