스프링 시큐리티란?

스프링 기반의 Application의 보안(인증과 인가)를 담당하는 프레임워크르 말한다. 스프링 시큐리티는 필터(Filter) 기반으로 동작하기 때문에 스프링 MVC와는 분리되어 관리 및 동작한다.

스프링 시큐리티 동작 방식

  1. 사용자의 요청이 서버로 인입된다.

  2. Filter Chain이 요청을 가로챈다.

    1. SecurityFilterAutoConfiguration에서 DelegatingFilterProxyRegistrationBean을 생성하고 getFilter를 이용해서 DelegatingFilterProxy라는 filter를 생성하고 처리를 위임한다.

      public class SecurityFilterAutoConfiguration {
      		// 생략 ...
          public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {
              DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean("springSecurityFilterChain", new ServletRegistrationBean[0]);
              registration.setOrder(securityProperties.getFilter().getOrder());
              registration.setDispatcherTypes(this.getDispatcherTypes(securityProperties));
              return registration;
          }
      }
      
      public class DelegatingFilterProxyRegistrationBean extends AbstractFilterRegistrationBean<DelegatingFilterProxy> implements ApplicationContextAware {
          // 생략 ...
          public DelegatingFilterProxy getFilter() {
              return new DelegatingFilterProxy(this.targetBeanName, this.getWebApplicationContext()) {
                  protected void initFilterBean() throws ServletException {
                  }
              };
          }
      
  3. 생성된 DelegatingFilterProxy 내부에 FilterChainProxy라는 위임 대상을 가지고 있다. FilterChainProxy는 SpringSecurity에서 제공되는 특수 필터로 SpringSecurityFilterChain이라는 이름을 가진 Bean을 호출하여 SecurityFilter의 역할을 수행한다.

    아래 이미지 처럼, Filter0과 Filter2 사이에 DelegatingFilterProxy가 Filter1 역할을 수행한다. 클래스명에서 알 수 있듯이 해당하는 필터가 직접 모든 처리를 하는 것이 아니라, 프록시 역할만 한다. 실제 처리는 등록된 SecurityFilterChain 그룹이 수행단다.

    SecurityFilterChain 그룹은 URL 기준으로 그룹핑을 맺는다. 그래서 어떠한 경우에는 해당 FIlter를 무시하고 통과하는 경우가 있고 그렇지 않은 경우가 존재한다.

    image.png

  4. SpringSecurityFilterChain은 List 형태로 구성 되어 있고 이 리스트를 AuthenticationFilter라고 부르며 등록된 Filters가 순차적으로 실행된다.

    1. UsernamePasswordAuthenticationFilter; 아이디, 패스워드를 이용한 인증을 담당하는 필터
      1. 동작 방식
        1. Reust로 넘어온 Username(Id)와 Password를 통해 UsernamePasswordAuthenticationToken을 생성한다.
        2. 참조하고 있는 AuthenticationManager에게 인증을 진행하도록 위임하다. (실제로 위임 받는 객체는 구현체인 ProviderManager 객체이다.)

스프링 시큐리티 적용

  1. build.gradle 스크립트에 Dependency 추가

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-security'
        testImplementation 'org.springframework.security:spring-security-test'
        implementation 'io.jsonwebtoken:jjwt:0.9.1'
    }
    
  2. 스프링 부트에서는 @EnableAutoConfiguration을 통해서 SecurityFilterAutoConfiguration 클래스를 Load하고 Default로 이름이 springSecurityFilterChain Bean을 등록해준다.

    @EnableWebSecurity(debug = true) // request가 들어 올 떄마다 어떤 filter를 사용하고 있는지 출력을 해준다.
    @EnableGlobalMethodSecurity(prePostEnabled = true) // 사전에 prePost로 권한 체크를 하는 설정
    @RequiredArgsConstructor
    public class SecurityConfig {
    
        private final UserService userService;
    
        @Value("${jwt.secret}")
        private String secretKey;
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
    	    // 인가(접근권한) 설정
    	    http.authorizeHttpRequests().antMatchers("/").permitAll();
    	    http.authorizeHttpRequests().antMatchers("/admin/**").hasRole("ADMIN"); 
    	    http.authorizeHttpRequests().antMatchers("/member/**").hasAnyRole("ADMIN", "MEMBER");
    	    http.authorizeHttpRequests().antMatchers("/user2/loginSuccess").hasAnyRole("3", "4", "5");
    		
    	    // 사이트 위변조 요청 방지
    	    http.csrf().disable();
    
    	    // 로그인 설정
    	    http.formLogin()
    		    .loginPage("/user2/login")
    		    .defaultSuccessUrl("/user2/loginSuccess")
    		    .failureUrl("/user2/login?success=100)")
    		    .usernameParameter("uid")
    		    .passwordParameter("pass");
    		
    	    // 로그아웃 설정
    	    http.logout()
    		    .invalidateHttpSession(true)
    		    .logoutRequestMatcher(new AntPathRequestMatcher("/user2/logout"))
    		    .logoutSuccessUrl("/user2/login?success=200");
    
    	    // 사용자 인증 처리 컴포넌트 서비스 등록
    	    http.userDetailsService(service);
    
    	    return http.build();
        }
    }
    
  3. Filter Chain이 적용되는 URL 설정 방법

    1. authenticated(); 인증된 사용자의 접근을 허용
    2. permitAll(); 모든 사용자에게 접근을 허용
    3. denyAll(); 모든 사용자에게 접근을 거부
    4. hasRole(Role); Role에 해당하는 사용자만 접근 허용
  4. 사용자 정의 Filter 생성

    Spring Boot 2.x.x - WebSecurituyConfigurerAdapter는 Filter Chain을 구성하는 Configuration 클래스로써 해당 클래스의 상속을 통해 Filter Chain을 구성할 수 있다.

JWT를 이용한 로그인 기능 구현

참고

https://sjh9708.tistory.com/170

https://velog.io/@mooh2jj/Security-인증인가처리

UsernamePasswordAuthenticationToken

UsernamePasswordAuthenticationFilter는 UsernamePasswordAuthenticationToken을 생성하여 AuthenticationManager에게 전달한다.

이 토큰에는 Client가 제출한 인증 정보가 포함되어 있다.