MSA-5. RefreshToken 적용기
다른 기능을 구현하기 위해 API 요구와 POST를 보니… 음… 리프레시 토큰을 써야 할 것 같았다. 아니! 써야만 했다. 그래서 기존 엑세스 토큰을 발급해 주고 로그인 문구를 띄워 주는 구조를 다 뜯어 고쳐야 했다.
뭐… 이런 식으로 흐름을 러프하게 잡았다. 충분히 할 수 있겠다는 생각이 들었다. 이 그림에서 로그인 기능은 1~2이고, 이 부분을 먼저 구현해야겠다고 생각하고 알음알음 코드를 작성했다.
처음 로그인 기능을 구현하였더니 404 에러가 떴다. 401도 아니고, 404…? 꿈이길… response body가 공백으로 떠서 어디서부터 어디를 고쳐야 할지 감도 안 오고… 도커로 띄워서 디버깅할 엄두가 안나 멘토님께 말씀 드렸더니 도커로 Springboot까지 띄워서 코드를 작성하고 있었고, (가이드에 적혀 있는 문장을 잘못 이해했음) 캐시 때문에 코드를 변경해도 반영이 안 되는 것이었다. 도커로 SQL, redis 같은 DB만 띄워 놓고, springboot는 IDE에서 했어야 했던 거였다. 그래서 찾기도 어려웠다.
도커로 Springboot를 내리고, SQL & Redis만 올려서 다시 빌드하니 403이 떴다.
403 외에도 자잘한 오류들이 있었다:
Parameter 2 of constructor in com.sun.sunboard.service.BoardService required a bean of type 'org.springframework.data.redis.core.RedisTemplate' that could not be found.
service에서는 RedisTemplate<String, String>을 사용했지만 config에서는 RedisTemplate<String, Object>를 사용해서 발생.
형식을 맞춰 주면 해결된다.
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| securityConfig defined in file [\SecurityConfig.class]
↑ ↓
| userService defined in file [\MemberService.class]
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default.
Update your application to remove the dependency cycle between beans.
As a last resort, it may be possible to break the cycle automatically
by setting spring.main.allow-circular-references to true.
Process finished with exit code 1
이런 오류도 있었다. 두 개의 클래스가 서로를 참조하고 있어서 참조 서클 에러가 발생했다. 이건 그냥 나눠 주면 된다. 필터 클래스를 작성할 때 WebSecurityConfigurationAdapter를 상속받았는데, Deprecated되었다는 에러가 났다.
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception{
return super.authenticationManagerBean();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
아래 레퍼런스에서 제시한 새로운 방식으로 작성하여 해결했다.
spring-security-without-the-websecurityconfigureradapter
403 에러는 SecurityConfig 클래스의 SecurityFilterChain 내에 PermitAll을 준 링크에 /login이 빠져있어서 그랬었다. 해당 부분을 수정하고, 404 에러를 해결하려고 했다가 더 꼬인 코드를 차근차근 풀어서 다시 작성하였다.
요약하자면 흐름은 아래와 같다:
- 최초 로그인 시 Refresh Token, Access Token을 클라이언트에게 발행하고 Access Token을 헤더에 저장하여 클라이언트에게 반환, Refresh Token은 Redis에 저장. > 로그인 이후 모든 요청은 헤더에 JWT 토큰을 담아서 요청한다.
- 로그아웃 시 발급한 Access Token을 Redis 블랙리스트에 등록.
- Refresh Token은 Access Token보다 기간을 길게 잡는다. 클라이언트가 만료된 Access Token으로 요청을 보낼 때 저장되어 있는 Refresh Token을 통해 Access Token을 새로 발급한다.
- Refresh Token도 만료되면 재로그인을 해야 한다.
Comments