Oauth2.0(카카오,네이버)을 사용해 로그인을 구현하던 중 access token은 발급이 잘 됐는데 토큰을 request로 받아 사용자 정보를 받아오는 과정에서 null 값이 발생했다.
사용자 인증은 Security, Jwt로 진행했다.
Tokenprovider.java
일단 jwt토큰을 생성할 때 payload의 sub claim은 memberId로 설정했다.
memberId는 카카오, 네이버에서 api로 제공하는 String Id 값이다.
LoginController.java
로그인 후에 postman으로 로그아웃을 진행하던 중에 401 에러가 났다.
userDetails 값이 null이었기 때문에 jwt관련 파일들을 디버깅 하며 살펴보았다.
Jwtfilter.java
request에서 토큰을 추출하는 과정에서 jwt가 null인 것을 확인했다. request에 Authorization 값은 정상적으로 들어오는 것을 확인했기 때문에 resolveToken 을 살펴보았다.
Jwtfilter.java
StringUtils.hasText(bearerToken) 으로 토큰이 존재하고 && startsWith(BEARER_PREFIX) 토큰이 BEARER_PREFIX으로 시작하면 토큰값을 리턴하게 되어있다.
하지만 아래 디버깅 내용을 보면 bearerToken은 "BEARER"로 시작하고 있고 내가 설정한 BEARER_PREFIX은 "Bearer "이었기 떄문에 null을 반환하고 있었던 것이다.
BEARER_PREFIX를 "BEARER"로 수정하고 나서 jwt는 정상적으로 토큰 값을 반환하게 되었다.
하지만 실행결과는 401->500에러로 바뀐것..
사용자를 찾을 수 없다는 에러였다.
Jwtfilter.java
sub로 담았던 memberId의 값이 잘 담겨져 있는 것을 볼 수 있다.
claim 중 sub 값을 추출해 loadUserByUsername을 호출했다.
UserDetailsServiceImpl.java
여기까지 온 순간 딱 알았다..토큰을 생성할 때, 받아올 때 모두 memberId를 사용해놓고 정작 사용자 정보를 찾을 때는 nickname과 비교해서 찾았으니 에러가 날 수 밖에 없었던 것이다.
memberRepository의 findByMemberId()로 수정한 후에 로그아웃도 잘 작동했다.
열심히 디버깅하고 원인을 찾았을 때는 별거 아니었다는 생각에 허무했지만
덕분에 수많은 예제들을 보고 정확한 이해없이 사용했던 jwt가 동작하는 과정을 꽤 꼼꼼하게 들여다볼 수 있었다.
간단한 디버깅 과정이었지만 스프링과 자바를 시작한지 두 달 된 나에게는 그리 쉽지 않다고 느껴졌다. 하지만 한 번 해봤으니 다음번엔 더 금방 해결할 수 있다는 자신감이 생겼다💫