logout

황상익·2024년 9월 9일

security

목록 보기
4/16

스프링 시큐리티는 기본적으로 DefaultLogoutPageGeneratingFilter를 통해 로그아웃 페이지 제공 “get/logout” URL로 접근이 가능
로그아웃 실행은 기본적으로 “ POST / logout “으로만 가능, CSRF 기능을 비활성화, 혹은 RequestMatcher를 사용할 경우 GET,PUT,DELETE 모두 사용 가능
로그아웃 필터를 거치지 않고 스프링 MVC에서 커스텀하게 구현할 수 있으며, 로그인 페이지가 커스텀하게 생성될 경우, 로그아웃 기능도 커스텀하게 구현

logoutAPI
http.logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer

.logoutUrl("/logoutProc") // 로그아웃이 발생하는 URL 을 지정한다 (기본값은 “/logout” 이다)
.logoutRequestMatcher(new AntPathRequestMatcher("/logoutProc","POST")) // 로그아웃이 발생하는 RequestMatcher 을 지정한다. logoutUrl 보다 우선적이다
// Method 를 지정하지 않으면logout URL이 어떤 HTTP 메서드로든 요청될 때 로그아웃 할 수 있다
.logoutSuccessUrl("/logoutSuccess") // 로그아웃이 발생한 후 리다이렉션 될 URL이다. 기본값은 "/login?logout"이다

.logoutSuccessHandler((request, response, authentication) -> { // 사용할 LogoutSuccessHandler 를 설정합니다.
response.sendRedirect("/logoutSuccess"); // 이것이 지정되면 logoutSuccessUrl(String)은 무시된다

})
.deleteCookies("JSESSIONID“, “CUSTOM_COOKIE”) // 로그아웃 성공 시 제거될 쿠키의 이름을 지정할 수 있다 
.invalidateHttpSession(true) // HttpSession을 무효화해야 하는 경우 true (기본값), 그렇지 않으면 false 이다
.clearAuthentication(true) // 로그아웃 시 SecurityContextLogoutHandler가 인증(Authentication)을 삭제 해야 하는지 여부를 명시한다
.addLogoutHandler((request, response, authentication) -> {}) // 기존의 로그아웃 핸들러 뒤에 새로운 LogoutHandler를 추가 한다 
(기존 + 새로 생성)
.permitAll() // logoutUrl(), RequestMatcher() 의 URL 에 대한 모든 사용자의 접근을 허용 함
  • LogoutFilter

client → logoutFIlter → requestMatcher -(요청 정보가 매칭 되는지)→ chain.doFilter (post 방식의 logout url이 오지 않은 경우)

client → logoutFIlter → requestMatcher -(요청 정보가 매칭 되는지)→ LogoutHandler → LogoutSuccessHandler

@Configuration
@EnableCaching
public class SecurityConfig {

    //메모리 상에서 사용자 설정
    //설정 파일과 중복이 있다면, @Bean 인메모리 방식이 우선
    @Bean
    public InMemoryUserDetailsManager inMemoryUserDetailsManager() {

        //User객체는 SpringSecurity가 갖고 있는 User
        UserDetails user = User.withUsername("user")
                .password("{noop}1111") //(noop)을 사용하면 평서문 처럼 사용 가능
                .authorities("USER")
                .build();

        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
                //SecurityFilterChainConfiguration -> filter 조건 성립 안됨
                //SecurityFilterChain -> Bean을 생성했기 때문 -> Bean이 없을 경우에만 성립된다. -> 사용자가 설정한 쪽으로 오게 된다.
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/logoutSuccess").permitAll()
                        .anyRequest().authenticated())
                .formLogin(Customizer.withDefaults())
                //.csrf(csrf -> csrf.disable()) //csrf 방식이 disable -> post 방식 뿐만 아니라 get 방식도 적용이 가능
                .logout(logout -> logout
                        .logoutUrl("/logout")
                        .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "POST")) //get 방식도 가능
                        .logoutSuccessUrl("/logoutSuccess") // 해당하는 Mapping 생성 logoutRequestMatcher 처리 안하면 post 방식만 가능
                        .logoutSuccessHandler(new LogoutSuccessHandler() {
                            @Override
                            public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                                response.sendRedirect("/logoutSuccess");
                                //복잡한 경로 -> handler 사용
                            }
                        })
                        .deleteCookies("JSESSIONID", "remember-me") //보통적으로 JSESSIONID는 삭제
                        .invalidateHttpSession(true) // logout시 session 무효화
                        .clearAuthentication(true) //securityContext 안에 있는 authentication 객체를 제거
                        .addLogoutHandler(new LogoutHandler() {
                            @Override
                            public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
                                //세션 무효화
                                HttpSession session = request.getSession();
                                session.invalidate();
                                //시큐리티 컨택스트 안에있는 authentication을 제거 가능 / 기존 authenticaiton 객체가 제거
                                SecurityContextHolder.getContextHolderStrategy().getContext().setAuthentication(null);
                                SecurityContextHolder.getContextHolderStrategy().clearContext(); //SecurityContextHolder 또한 clear
                            }
                        })

                        .permitAll() //logoutProc
                );


        return http.build(); // securityFilterChain 생성된다.
    }
}
profile
개발자를 향해 가는 중입니다~! 항상 겸손

0개의 댓글