본문 바로가기

Spring Security

[Spring Security] 기본 API 및 Filter 이해(1)

이번 포스팅에서는 스프링 시큐리티를 크게 3가지로 알아보려고 합니다.

  • Spring Security 의존성 주입 및 보안기능
  • UserNamePasswordAuthenticationFilter 동작원리
  • LogoutFilter 동작원리
Spring Security 의존성 주입 및 보안기능

먼저 의존성을 추가하기 위해 아래와 같이 코드를 추가해줍니다. (Gradle 기준)

implementation 'org.springframework.boot:spring-boot-starter-security'

의존성을 주입하고 서버를 실행하게 되면 아래와 같은 일들이 자동으로 일어나게 됩니다.

  1. 시큐리티의 초기화 작업 및 보안설정이 이루어지게 됩니다.
  2. 별도의 설정을 하지 않아도 기본적인 보안기능이 현재 시스템에 적용됩니다.

기본적인 보안기능이라하면 아래와 같습니다.

  • 기본 로그인 페이지 제공
  • 기본계정 제공 (user / 랜덤문자열)

하지만, 이런 기본적인 기능들을 현재 시스템에 적용해도 큰 메리트가 없기때문에 스프링 시큐리티는 세부적인 보안기능을 설정할 수 있는 API를 제공합니다.

 

먼저, 세부적인 보안기능을 설정하려면 WebSecurityConfigurerAdapter클래스를 상속받아야 합니다.

WebSecurityConfigurerAdapter클래스를 상속 받은 후, configure메소드를 오버라이드 하여 현재 시스템에 필요한 기능에 맞는 API를 호출하여 설정하면 됩니다.

 

예를들어 로그인을 한다고 가정했을때, 각 API는 아래와 같이 동작하게 됩니다.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    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")  // 로그인 Form action URL
            .successHandler(new AuthenticationSuccessHandler() {
                @Override
                public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                    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");
                }
            });
    }
}

 

 

UserNamePasswordAuthenticationFilter 동작원리

UserNamePasswordAuthenticationFilter 필터는 FormLogin 인증처리를 담당하는 필터입니다.

인증처리를 하는 방식을 자세히 살펴보면 아래와 같은 Flow로 진행되는 것을 알 수 있습니다.

이 필터에 동작방식을 코드로 보기위해 어떤 클래스가 사용되고 있는지 알아보도록 하겠습니다.

  • AbstractAuthenticationProcessingFilter.java
  • UserNamePasswordAuthenticationFilter.java
  • ProviderManager.java

먼저 AbstractAuthenticationProcessingFilter클래스의 doFilter가 실행되면서 아래와 같이 로직이 실행되게 됩니다.

 

1. AntPathRequestMatcher(/login) : Form action의 url이 login인지 확인해서 맞으면 AUthentication객체를 생성하고 아니면 다음 필터로 넘어갑니다.

AbstractAuthenticationProcessingFilter

 

2. Username과 password를 가지고 Authentication객체를 생성한다.

AbstractAuthenticationProcessingFilter

이때 attemptAuthentication메소드가 실행되게 되는데, 저 메소드는 UserNamePasswordAuthenticationFilter클래스에 구현되어 있고, username/password를 통해 만든 토큰을 AuthenticationManager에게 전달하여 인증이 성공하면 Authentication객체를 반환받습니다.

UserNamePasswordAuthenticationFilter

 

3. AuthenticationManager에게 객체생성을 위임합니다.

UserNamePasswordAuthenticationFilter

 

4. SecurityContext에 저장

AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter

 

LogoutFilter 동작원리

LogoutFilter 필터는 로그아웃 처리를 담당하는 필터입니다.

로그아웃 방식을 자세히 살펴보면 아래와 같은 Flow로 진행되는 것을 알 수 있습니다.

이 필터에 동작방식을 코드로 보기위해 어떤 클래스가 사용되고 있는지 알아보도록 하겠습니다.

  • LogoutFilter.java
  • SecurityContextLogoutHandler.java

먼저 LogoutFilter클래스의 doFilter가 실행되면서 아래와 같이 로직이 실행되게 됩니다.

 

1. 요청 url이 logout인지 확인합니다.

LogoutFilter

 

2. 요청 url이 logout이 맞을경우 SecurityContext에서 Authentication객체를 가져옵니다.

LogoutFilter

 

3. SecurityContextLogoutHandler에서 세션무효화, 쿠키삭제, SecurytiContext객체를 삭제하고 인증객체도 null값으로 변경합니다.

LogoutFilter

 

SecurityContextLogoutHandler