회고록

[Numble 챌린지 개발일지] 5주차 (1) 로그아웃 리디렉션 해결

UL :) 2022. 12. 15. 01:19

 

앞서 쿠키의 secure 설정을 true로 하면 https로만 통신해야하기 때문에

 

마감일정이 촉박한 이 시점에서 😭 서버에 SSL 인증서까지 발급받아 적용하기에는 시간적 무리가 있었습니다. 그래서 일단 http 쿠키의 secure 옵션을 false로 해뒀습니다.

 

이어서 포스트맨으로 로그인, 로그아웃 테스트를 해보았습니다.

 

 

이렇게 Authorization 헤더에 액세스 토큰이 담겨오고, 쿠키에는 리프레쉬 토큰이 담겨옵니다.

 

 

포스트맨에는 쿠키가 자동으로 설정됩니다.

 

로그인이 되었으니 로그아웃을 테스트를 해보겠습니다!

 

참고로 스웨거에서는 쿠키를 받을 수 없는 문제가 있습니다. 원인은 아래와 같습니다.

 

왜 Swagger는 쿠키를 받을 수 없을까 + 해결방법

참고한 포스팅

 

  • 쿠키 인증은 웹 페이지가 프로그래밍 방식 으로 특정 헤더를 수정하지 못하도록 하는 브라우저 보안 제한 으로 인해 현재 Swagger UI 및 Swagger 편집기에서 작동하지 않습니다
  • 그런데 Swagger 설명서 에 쿠키 인증 섹션이 있는 이유는?
    • 해당 문서는 OpenAPI 구문 가이드입니다. OpenAPI 사양에서는 API 정의에서 쿠키 인증을 설명할 수 있습니다.
    • Swagger 도구(편집기, UI 등)는 OpenAPI 사양의 특정 구현입니다. Swagger Editor/UI는 브라우저에서 완전히 클라이언트 측에서 실행되는 웹 페이지이므로 금지된 헤더, CORS 등과 같은 브라우저 보안 메커니즘의 적용을 받습니다.
  • 다른 도구는 구현 및 런타임 환경에 따라 동일한 제한이 있을 수도 있고 없을 수도 있습니다. 예를 들어 swagger-api/swagger-js#1163 에서 논의된 해결 방법 중 하나는
    • 서버 측 애플리케이션을 통해 요청을 프록시하여 브라우저 제한을 해결하는 것입니다.
    • SwaggerHub가 이를 수행하므로 SwaggerHub에서 호스팅되는 API 문서에서 쿠키 인증이 작동합니다.

 

 

해결하기에는 시간이 부족하다고 판단되어... 포스트맨으로 테스트 했습니다. 😅

 

GET으로 리다이렉트 되는 문제가 발생했다.


아니 분명히 POST로 보냈는데. GET으로 보내지 말라는 소리를...

포스트맨 콘솔을 보니

 


/logout POST로 잘 갔다가 /login?logout GET으로 이상하게 리다이렉트 되는 것을 알 수 있습니다.

 

아.. 그렇다면 그냥 SecurityContextLogoutHandler를 활용해서 GET방식으로 로그아웃 처리를 하면 안되나? 싶었는데...

 

스프링 시큐리티에서 디폴트 로그아웃은 POST로 설정이 되어있기도 하고, 찾아보니 여러모로 로그아웃은 POST로 하는 이유가 있었습니다.

 

로그아웃은 왜 POST로 해야하는지?

spring 공식 문서에서 다음과 같은 내용을 찾을 수 있었습니다.

 

 

인프런 김영한 강사님 QNA에서도 이유를 알 수 있었습니다.

 

  • 로그아웃은 클라이언트에서 서버로 요청하는 것입니다. 따라서 GET, POST 등에서 선택해야 합니다. 내부적으로 상태가 변하므로 POST를 선택했습니다.

 

또한 별개로 JWT로 전달되는 인증정보를 다시 DB와 대조해야 하는가에 대해서 고민 중이었는데 이 QNA에서 인사이트를 얻었습니다.

 

  • 쿠키가 존재하더라도 해당 시점에 회원이 탈퇴하거나, 여러가지 이유로 회원 데이터가 제거될 수 있습니다(운영 정책상 회원이 차단되거나 등등)

 

쿠키를 토큰으로 치환해서 생각해도 똑같이 적용될 수 있지 않을까?... JWT 토큰이 존재하더라도, 해당 시점에 회원 데이터가 제거 되었을 수 있으므로 곧장 데이터를 갖다 쓰지않고 DB의 회원과 대조해서 확인하는 코드를 추가했습니다.

 

 

 

잠깐 딴길로 샜는데, 어쨌든 결론적으로 로그아웃을 POST 메서드로 유지하되 리다이렉트 되는 문제를 해결해야합니다.

 

알아보니 기본적으로 Spring Security는 로그아웃 성공 후 /login?logout 으로 리디렉션을 합니다.

 

이것을 막고 싶으면  LogoutSuccessHandler 를 사용하여  HttpStatus 200을 반환하면 됩니다.

 

        http  
                .logout()  
                .logoutUrl("/logout")  
                .deleteCookies("refreshToken"); //로그아웃 후 쿠키 삭제
                .addLogoutHandler(jwtLogoutHandler) //DB에서 RT 삭제

SercurityConfig의 원래 이랬던 코드를

        http  
                .logout().permitAll()  
                .logoutUrl("/logout")  
                .deleteCookies("refreshToken") //로그아웃 후 쿠키 삭제
                .addLogoutHandler(jwtLogoutHandler) //DB에서 RT 삭제  
                .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK));

 

이렇게 변경했더니 해결되었습니다!