웹 프로그래밍/[ Spring Security ]

[ Spring Security ] 00. LoginForm 인증 API 및 Filter의 이해

kim.svadoz 2021. 12. 6. 16:27
728x90
반응형
인프런에서 진행하는 정수원 강사님의 "스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security" 강의를 보고 학습을 위해 개인적으로 추가/정리한 글임을 알립니다.

[ Login 인증 ] UsernamePasswordAuthenticationFilter

SecurityContext : 인증 필터가 사용자의 인증을을 가지고 있는 Context

SecurityContextHolder.getContext().getAuthentication() : 어디서든 현재 어떤 인증을 받았는지 볼 수 있다.

protected void configure(HttpSecurity http) throws Exception {
    http.formLogin()
        .loginPage("/login.html")                     // 사용자 정의 로그인 페이지
        .defaultSuccessUrl("/home")                 // 로그인 성공 후 이동 페이지
        .failureUrl("/login.html?error=true")          // 로그인 실패 후 이동 페이지
        .usernameParameter("username")                 // 아이디 파라미터명 설정
        .passwordParameter("password")                 // 패스워드 파라미터명 설정
        .loginProcessingUrl("/login")                 // 로그인 Form Action Url
        .successHandler(loginSuccessHandler())         // 로그인 성공 후 핸들러
        .failureHandler(loginFailureHandler())          // 로그인 실패 후 핸들러
    ;
}
// 실제 사용 코드
protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated();
        http
                .formLogin()
                .loginPage("/loginPage") // 직접 만든 로그인 페이지로 이동하도록 설정
                .defaultSuccessUrl("/")
                .failureUrl("/login")
                .usernameParameter("userId")
                .passwordParameter("passwd")
                .loginProcessingUrl("/login_proc")
                .successHandler(new AuthenticationSuccessHandler() { // 로그인 성공 시 호출하는 핸들러
                    // handler
                })
                .failureHandler(new AuthenticationFailureHandler() { // 로그인 실패 시 호출하는 핸들러
                    // handler
                })
                .permitAll() // 로그인 페이지는 인증을 받지 않아도 되도록.
        ;
    }

 

> 인증과정

image-20211120130747378

Request가 들어오면 UsernamePasswordAuthenticationFilter로 들어오게 되고 Authentication(Username + Password) 객체를 AuthenticationManager로 보낸다.

 

AuthenticationManagerAuthenticationProvider에게 인증처리를 맡기고, 인증에 실패하면 예외를 발생하고 인증에 성공하면 다시 AuthenticationManager가 필터에게 전달해서 Authentication(User + Authorities) 객체를 넘기면 이 정보를 SecurityContext에 저장하고 SuccessHandler로 이후 작업을 수행한다.

 

FilterChainProxy는 Filter를 관리하는 Bean인데 이 프록시가 가지는 여러 기본적인 필터 Bean들이 있다.

.formLogin()을 실행하면 여러 API에 관련된 필터들이 생성이 된다. 그래서 이 FilterChainProxy는 각각의 필터들을 순서대로 사용자 요청을 처리할 수 있도록 호출해준다.

image-20211120130855890

 

[ Logut 처리 ] LogoutFilter

Logout 요청(/logout)이 들어오면 Security가 이 요청을 받고 로그아웃 처리를 한다.

  1. 세션을 무효화하고
  2. 인증토큰을 삭제하고 (SecurityContext 등)
  3. 쿠키정보도 삭제하고
  4. 로그인 페이지로 리다이렉트

의 순서로 진행된다.

protected void configure(HttpSecurity http) throws Exception {
    http.logout()                                            // 로그아웃 처리
        .logoutUrl("/logout")                                 // 로그아웃 처리 URL
        .logoutSuccessUrl("/login")                               // 로그아웃 성공 후 이동 페이지
        .deleteCookies("JSESSIONID", "remember-me")               // 로그아웃 후 쿠키 삭제
        .addLogoutHandler(logoutHandler())                      // 로그아웃 핸들러
        .logoutSuccessHandler(logoutSuccessHandler())           // 로그아웃 성공 후 핸들러
    ;
}
// 실제 사용 코드
protected void configure(HttpSecurity http) throws Exception {    
    http
        .logout()
        .logoutUrl("/logout") // default 는 logout , SpringSecurity는 기본적으로는 post방식으로 logout처리한다.
        .logoutSuccessUrl("/login") // logout후 이동할 페이지를 설정
        .addLogoutHandler(new LogoutHandler() {
            @Override
            public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
                HttpSession session = request.getSession();
                session.invalidate();
            }
        })
        .logoutSuccessHandler(new LogoutSuccessHandler() { // logout 후 호출하는 핸들러
            @Override
            public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                response.sendRedirect("/login");
            }
        })
        .deleteCookies("remember-me") // remember-me 라는 쿠키가 삭제된다.
        ;

}

 

> 인증과정

image-20211120130814528

기본적으로는 POST 방식으로 Request를 받아서 해당 요청은 LogoutFilter로 이동한다.

 

Filter는 SecurityContext로부터 Authentication 객체를 꺼내와서 SecurityContextLogoutHandler로 가져온다.

 

이 핸들러가 세션을 무효화 하고, 쿠키를 삭제하고 SecurityContextHolder.clearContext()를 수행한다.

(get 방식으로 로그아웃을 처리할 때도 이 SecurityContextLogoutHandler에서 처리한다.)

 

로그아웃 핸들러가 성공적으로 종료되면 SimpleUrlLogoutSuccessHandler가 login페이지로 리다이렉트 해준다.

image-20211120130831816

 

다음 시간에는 Spring Security 에서 제공하는 Remember Me 인증 API에 대해서 알아볼 것이다.

728x90
반응형