Spring Security : Logout Filter + API

    이 포스팅은 인프런 정수원님의 강의를 복습하며 정리한 글입니다. 

    Logout

    일전에 Login은 사용자 인증이 완료되면, 인증 객체를 만들고 Security Context에 저장했고, 또한 인증 객체 관련해서 세션을 생성해서 JSESSION ID를 내려주면서 구현했다. Logout 기능을 구현해주기 위해서는 Login에서 했던 것들을 하나하나 무효화해주면 된다.

    1. Security Context에 있는 인증 객체 삭제
    2. 세션 무효화 
    3. 쿠키 정보 삭제 

    스프링 시큐리티의 Logout API를 사용하면, 위의 과정들을 하나하나 처리할 수 있는 것은 물론이고, 로그아웃 후 리다이렉트 하는 위치까지 지정할 수 있게 된다. 

    실제로는 위와 같은 일을 하는 것으로 이해를 할 수 있겠다. 

     

    Spring Security Logout API 

    Spring Security에서는 Logout API를 통해서 사용자가 하나하나 Logout을 구현하지 않도록 편의 기능을 제공해준다. 

    • logout() : 로그아웃 처리를 해준다. 
    • logoutUrl() : 로그아웃 처리 URL 설정
    • logoutSuccessurl() : 로그아웃 후 리다이렉션 할 페이지 설정
    • deleteCookies() : 로그아웃 할 때, 삭제할 쿠키. → 주로 "JSESSIONID", "Remember-me"
    • addLogoutHandler() : 로그아웃 할 때, 사용자가 지정한 행동을 하고 싶을 때 
    • logoutSuccesHandler() : 로그아웃 성공 후, 개발자가 추가하고 싶은 기능이 있을 때 추가한다. 

    실제로 작성한 코드는 다음과 같은데, Handler이 어떤 조건에서만 동작하는 것처럼 보인다. 지금은 내부 구조를 정확하게 잘 모르기 때문에, 우선은 logoutUrl이나 이런 것들을 사용하기 위해서는 저런 형태로 사용해야한다고 이해하고 넘어가고자 한다. 

    추후에 이런 부분에 대한 이해를 알게 되면 업데이트를 하겠다. 

     

    Spring Security Logout 내부구조 동작

    Logout의 버튼을 누르는 순간부터 위의 로직이 동작한다. (/logout URL 접근하는 것만으로는 아무 일도 일어나지 않음)

    1. 현재 요청이 /logout이 맞는지 AntPathRequestMatcher를 이용해서 확인한다. 아니라면, 다른 요청이기 때문에 다음 필터로 넘겨준다.
    2. 로그아웃 요청이 왔다고 하면, Security Context로부터 인증객체를 꺼낸다.
    3. 꺼낸 인증객체를 SecurityContextLogoutHandler에게 전달해준다. 
    4. LogoutHandler는 세션 무효화, 쿠키 삭제, SecurityContextHolder.clearContext()를 이용해 로그아웃 처리를 해준다.
    5. 처리가 완료되면, Logout Filter는 리다이렉트 URL을 따라 리다이렉팅 해준다. 

     

     

    Spring Security Logout 코드 따라까보기

    먼저 다음 Logout 버튼을 눌러준다. Logout 버튼을 눌러주면, POST 형식으로 Logout 요청이 간다. 

    LogoutFilter

    LogoutFilter에 사실상 모든 로직이 들어가있다. 먼저 if의 조건문에서 현재 요청이 /logout으로 온지 확인하는 절차가 진행된다. 

    AntPathRequestMatcher

    현재 요청 경로가 /logout에 매칭되는지 확인하러 AntAPthRequestMatcher로 넘어오게 된다. 정상이므로 True로 반환이 된다.

    LogoutFilter

    반환된 후, SecurityContextHolder에서 SecurityContext를 가져온다. 그리고 SecurityContext에 인증된 Auth 객체를 가져온다.

    여기서 볼 수 있듯이, 로그인한 후에 Auth 객체를 가져오면 Null 값이 아니라 실제로 인증 토큰이 들어있는 것을 볼 수 있다.

    LogoutFilter

    먼저 handler를 통해서 logout 처리가 되는 것을 볼 수 있다. 이걸 좀 더 따라가보겠다.

    Composited Logout Handler

    Composited Logout Handler로 넘어오게 된다. 옆에 적혀있는 사이즈를 보면 Handler가 5개가 있는 것을 알 수 있고, For문을 돌면서 각 Hanlder로 필요한 처리를 해주는 것을 이해할 수 있다. 

    CookieClearingLogoutHandler

    쿠키 클리닝 로그아웃 핸들러까지 들어가게 된다. 여기서 확인할 수 있는 것은 가지고 있던 쿠키를 지운다는 것이었다. 

    내가 등록한 Handler

    그 다음에는 addLogOutHandler에서 익명 클래스로 등록한 Handler가 되는 것을 확인할 수 있다. 즉, addLogoutHandler로 만들어진 Handler는 다른 Handler를 대체하는 것이 아니라 Iterator 속으로 들어가서 For 문 형태로 한번씩 실행되는 것을 볼 수 있다. 

    SecurityContextLogoutHandler

    SecurityContextLogoutHandler로 넘어와서는 Session을 꺼내와서 Invalid 메서드를 이용해서 무효화 처리해주는 것까지 확인할 수 있다. 

    SecurityContextLogoutHandler

    또한, SecurityContextHolder 클래스에서 SecurityContext를 가져오고, 그 Sercurity Context에서 인증 객체를 삭제하고, null값을 넣어주어 인증되었던 기록을 다 지워주는 것을 확인할 수 있다. 

    LogoutFilter

    그 후로는 logoutSuccessHandler를 통해서 성공 후 해야할 일을 처리해주는 것까지 확인할 수 있다. 

    만약 이 때, 사용자 LogoutSuccessHandler를 등록해주었다면, 기존의 Default LogoutSuccessHandler는 사용되지 않는다. 오로지 사용자가 등록한 LogoutSuccesHandler로만 넘어와 정해진 코드를 수행한다. 

     

    위 코드의 구조적 정리

    위 코드를 하나씩 따라가보면 다음과 같이 움직인 것을 볼 수 있다.

    1. 가장 먼저 SecurityContextHolder 객체에서 인증 객체를 가지고온다.
    2. 인증객체를 LogoutHandler에게 넘겨줘서 인증도 무효화하고, 세션까지 무효화재누는 식으로 접근을 한다. 
    3. 그리고 SuccessHandler를 통해서 로그아웃 후 필요한 일을 처리해준다. 

     

     

    정리 

    • 스프링은 Logout API를 제공해서 개발자가 편리하게 로그아웃 기능을 구현하게 해준다.
    • 스프링의 LogOut은 버튼을 누르면 실행되는데 POST 방식으로 요청된다.
    • 요청이 오면 LogoutHandler는 For문을 통해서 순회한다. 따라서 유저가 추가한 logoutHandler는 For문에 포함되서 같이 일을 한다. 기본적으로 세션 무효화 및 인증객체 삭제를 해준다.
    • successLogoutHandler는 개발자가 만든 것을 추가하면, Default로 등록된 Handler는 더 이상 사용하지 않는다. 

    댓글

    Designed by JB FACTORY