관리 메뉴

bright jazz music

[Spring security] 1.5 Logout 처리, LogoutFilter 본문

Framework/Spring Security

[Spring security] 1.5 Logout 처리, LogoutFilter

bright jazz music 2022. 9. 11. 00:11

 

 

  • http.logout() : 로그아웃 기능 작동
  • logoutUrl("/logout") : 로그아웃 처리 되는 URL 입력
  • logoutSuccessUrl("/login") : 로그아웃 성공 후 이동할 페이지. 예문에서는 로그아웃 후 /login으로 이동한다.
  • deleteCookies("JSESSIONID", "remember-me") : 로그아웃 후 쿠키 삭제, remember-me는 로그아웃 후에도 로그인 없이 접근 가능하도록 하는 쿠키
  • addLogoutHandler(logoutHandler()) : 로그아웃 됐을 떄 스프링 시큐리티가 기본적으로 제공하는 로그아웃 구현체가 있다. 그 구현체에서 실제로 세션을 무효화하고 인증 토큰을 삭제하는 등의 처리를 한다. 그러한 기본적인 처리 외에 추가적인 처리를 하고 싶을 때 로그아웃 핸들러 인터페이스를 구현해서 직접 클래스를 만들서 그 설정을 해주고 파라미터로 넣어주면 여기서 처리가 된다.
  • logoutSuccessHandler(logoutSeccessHandler) : 로그아웃 성공 후 후속 작업을 하는 핸들러. 이 역시 logoutSuccessHandler 인터페이스를 구현한 클래스를 만들고 로직을 넣은 뒤 그걸 파라미터로 넣어준다.

 

 

그리고 스프링 시큐리티는 로그아웃을 할 때 원칙적으로는 포스트 방식으로만 처리한다. get으로 구현하면 오류 발생한다. 그러나 설정을 통해 get으로도 로그아웃 처리를 할 수 있다.

 

코드로 알아보기

package io.security.basicsecurity;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@Configuration //설정파일이므로
@EnableWebSecurity //여러 클래스들을 임포트 해서 실행시키는  어노테이션이다. 그래야 웹 보안이 활성화 된다.
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http
                .authorizeRequests()    //요청에 대한 보안검사 시작
                .anyRequest().authenticated(); //어떤 요청에도 인가 받도록 설정. 안 받으면 접근 불가
        //그래서 인가를 받기 위해 /loginPage로 이동한다. 근데 이 경로도 인가가 필요하다.
        //그래서 이 경로는 인가를 받지 않아도 접근 가능하도록 처리한다.
        // .permitALL()을 붙여줘서 /loginPage로의 접근은 인가르 받지 않아도 되도록 처리한다.

        //이제 인증방식
        http
                .formLogin();
//                .loginPage("/loginPage")
//                .defaultSuccessUrl("/")
//                .failureUrl("/login")
//                .usernameParameter("userId")
//                .passwordParameter("passwd")
//                .loginProcessingUrl("/login_proc")
//                .successHandler(new AuthenticationSuccessHandler() { //로그인에 성공했을 떄 성공 핸들러. AuthenticationSuccessHander 구현체를 넣어주면 된다. 우리는 걍 익명 클래스 사용
//                    @Override
//                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//                        //request, response, authentication 인증에 성공했을 때 그 결과를 담은 인증 객체까지 파라미터로 전달되어서 넘어온다.
//                        //이걸 활요해서 구체적인 로직을 구현하면 된다.
//                        System.out.println("authentication : " + authentication.getName());
//                        response.sendRedirect("/"); //루트페이지로 이동
//                    }
//                })
//                //실패하면 아래의 실패 핸들러 호출
//                .failureHandler(new AuthenticationFailureHandler() {
//                    @Override
//                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
//                        //인증 예외 객체를 파라미터로 전달 받는다.
//                        System.out.println("exception : " + exception.getMessage()); //예외 메시지 출력
//                        response.sendRedirect("/login");
//                    }
//                })
//                .permitAll();

        http
                .logout()
                .logoutUrl("/logout") //기본값은 /logout. 그리고 스프링 시큐리티는 기본적으로 POST방식으로 로그아웃 한다. 따라서 GET을 쓰면 오류난다. 그러나 GET으로 할 수 있는 방법도 있다.
                .logoutSuccessUrl("/login")
                .addLogoutHandler(new LogoutHandler() { //기본 외에 추가 작업을 위해 넣어줌
                    @Override
                    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
                        HttpSession session = request.getSession();
                        session.invalidate();
                    }
                })
                .logoutSuccessHandler(new LogoutSuccessHandler() {//logoutSuccessUrl과 비슷하지만 handler는 단순히 경로를 지정해 주는 것 뿐만 아니라 로직을 넣을 수 있다.
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.sendRedirect("/login");

                    }
                })
                .deleteCookies("remember-me"); //쿠키 삭제. remember-me로 발행된 쿠키 삭제


    }
}

 

 

 

 

 

post로 되어 있다.

 

 

 

 

 

 

로그아웃 필터에 대해서

 

request는 원칙적으로 POST방식.

 

로그아웃 필터가 요청을 받아서  AntPathReqeustMatcher에 넘김. 그것은 이 것이 /logout을 요청하고 있는지 검사. 일치하지 않으면 NO  일치하면 SecurityContext에서 Authentication (인증)객체를 꺼내와서 SecurityContextLogoutHandler에게 전달한다. 로그아웃 필터는 여러 개의 핸들러를 가지고 있는데, dl SecurityContextHandler는 다음과 같은 일을 한다.

- 세션 무효화

- 쿠키 삭제

- SecurityContextHolder.clearContext(): 시큐리티 컨텍스트에서 객체 삭제. 그리고 거기서 가져온 인증 객체도 null로 초기화 한다. 사실상 이걸로 로그아웃까지의 처리는 끝이다. * get방식으로 로그아웃 처리를 할 때도 이 핸들러를 이용한다.

 

이렇게 해서 로그가웃 핸들러가 성공적으로 종료되면 필터는 SimpleUrLogoutSuccessHandler 클래스를 호출해서 로그인 페이지로 이동하도록 처리한다.(커스텀 가능)

 

 

 

1,2,3,4는 기본 제공. 0번은 우리가 만든 임시 클래스. 총 5개.

Comments