프로젝트 생성

  • Spring Boot: 3.1.5

  • Java: 17

  • Spring Boot Security: 6.1.5

  • SecurityConfig 설정파일

    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig {
    
        ...
    
        @Bean
        public WebSecurityCustomizer webSecurityCustomizer() {
            return (web) -> web
                    .ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations());
        }
    
        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            http
                    .authorizeHttpRequests((authz) -> authz
                            .requestMatchers("/mypage").hasRole("USER")
                            .anyRequest().authenticated()
                    );
    
            http
                    .formLogin((form) -> form
                            .loginPage("/login")
                            .defaultSuccessUrl("/")
                            .successHandler(authenticationSuccessHandler)
                            .failureHandler(authenticationFailureHandler)
                            .permitAll()
                    );
              
            return http.build();
        }
    
        ...
    
        }
    }


URL 요청 시 인가 처리 흐름

  1. AuthorizationFilter는 URL 기반 인가 처리를 담당하는 필터이다.

  2. AuthorizationFilterdoFilter() 메서드 호출

    • URL 기반으로 인가 처리를 하는 경우에는 AuthorizationManagerRequestMatcherDelegatingAuthorizationManager 클래스를 사용한다. this.authorizationManagerRequestMatcherDelegatingAuthorizationManager를 주입받은 것을 아래 사진에서 확인할 수 있다.
    • check() 메서드의 파라미터에 권한 심사에 필요한 정보를 담는다.
      • this:getAuthentication: SecurityContextHolderStrategy로 부터 인증 정보 얻는다.
      • request: 요청 정보
  3. RequestMatcherDelegatingAuthorizationManagercheck() 메서드 호출
    RequestMatcherDelegatingAuthorizationManagerAuthorizationManager의 구현체로 RequestMatcher 평가식을 기반으로 평가식에 매치되는 AuthorizationManager 구현클래스에게 권한 심사를 위임한다.

    • RequestMatcherDelegatingAuthorizationManager 클래스의 mappings 필드는 RequestMatcherEntry 객체로 구성된 리스트이다. RequestMatcherEntry 객체는 requestMatcher에 경로를 entryAuthenticaionManager 구현체를 담고있다.

      3-1. matcher() 메서드를 통해 mappingsrequestMatcher와 파라미터로 넘어온 request의 URI가 매칭되는지 확인한다. 매칭되는 경우 while문을 빠져나간다.

      3-2. mapping.getEntry() 로 인가처리를 위임할 AuthorizationManager 구현클래스를 꺼낸다.

      3-3. 찾은 AuthorizationManager 구현체에게 인가처리를 위임한다.

  1. 찾은 AuthorizationManager 구현체check() 메서드가 호출되고 사용자의 권한을 심사한다.

    • 적절한 권한이라면 AuthorizationDecision[granted=true]을 반환한다.
    • 적절하지 않은 권한이라면 AuthorizationDecision[granted=false]을 반환한다.
  2. RequestMatcherDelegatingAuthorizationManager 에서 반환받은 AuthorizationDecisionAuthorizationFilter로 반환한다.

  3. AuthorizationFilterAuthorizationDecision을 반환받았다.

    • AuthorizationDecision[granted=true]을 반환받으면 다음 필터를 호출한다.
    • AuthorizationDecision[granted=false] 을 반환받으면 AccessDeniedException 을 던지고 ExceptionTranslationFilterAccessDeniedException()을 처리한다.

로그인하지 않고 /mypage를 호출했을 경우 인가 처리 흐름

  1. AuthorizationFilterdoFilter() 메서드 호출
  2. RequestMatcherDelegatingAuthorizationManagercheck() 메서드 호출
    RequestMatcherDelegatingAuthorizationManagermappings 필드를 보면 /mypage 요청을 처리할 AuthorizationManager 구현체는 AuthorityAuthorizationManager이다.
  3. AuthorityAuthorizationManagercheck() 메서드 호출
    AuthorityAuthorizationManager/mypage의 권한정보인 ROLE_USER를 가지고 있다. AuthoritiesAuthorizationManagercheck() 메서드를 호출하면서 인증정보와 권한정보를 넘긴다.
  4. AuthoritiesAuthorizationManagercheck() 메서드 호출
    여기서 인가 처리가 이루어 진다. 현재 로그인을 하지 않았으므로 인증 객체가 AnonynousAuthenticationtoken이며 권한이 ROLE_ANONYMOUS이다. /mypage에 접근하려면 ROLE_USER권한을 가져야 하므로 AuthorityAuthorizationDecision[granted=false] 을 반환한다.
  5. AuthorityAuthorizationDecisionAuthoritiesAuthorizationManager -> AuthorityAuthorizationManager -> RequestMatcherDelegatingAuthorizationManager -> AuthorizationFilter 를 따라 반환된다.
    decision.isGranted()=false이므로 AccessDeniedException 예외를 던진다.

참고 | RequestMatcherDelegatingAuthorizationManager의 mappings 필드 초기화

초기화 될 때 스프링 시큐리티가 SecurityConfig 파일 읽어 RequestMatcherAuthorizaionManager 구현체를 생성해 RequestMatcherDelegatingAuthorizationManagermappings 필드 초기화한다.

  • AuthorizedUrlhasRole() 메서드
    SecurityConfig파일에서 USER를 읽어와AuthorityAuthorizationManager 객체 생성하면서 USER 권한정보를 넘긴다.
  • AuthorizationManagerRequestMatcherRegistry 클래스의 addMapping() 메서드
    managerBuilder에 생성한 MvcRequestMatcher[pattern='/mypage']AuthorityAuthorizationManager[authorities=[ROLE_USER]] add한다.
  • RequestMatcherDelegatingAuthorizationManagermappings 필드에 managerBuilder에 저장된 값들이 전달된다.

로그인하고 /mypage를 호출했을 경우 인가 처리 흐름

로그인하지 않고 /mypage를 호출했을 경우와 1,2,3번까지는 동일하다.
ROLE_USER권한을 가진 사용자가 로그인하고 /mypage를 호출했을 경우를 알아보자.

  1. AuthoritiesAuthorizationManagercheck() 메서드 호출
    여기서 인가 처리가 이루어진다. 현재 로그인 했으므로 인증 객체가 UsernaePasswordAuthenticationToken이며 권한은 ROLE_USER이다. /mypage에는 ROLE_USER권한을 가진 사용자만 접근할 수 있는데 현재 사용자는 ROLE_USER권한을 가진다. 따라서 AuthorityAuthorizationDecision[granted=true] 을 반환한다.
  2. AuthorityAuthorizationDecisionAuthoritiesAuthorizationManager -> AuthorityAuthorizationManager -> RequestMatcherDelegatingAuthorizationManager -> AuthorizationFilter 를 따라 반환된다.
    decision.isGranted()=true이므로 정상적으로 다음 필터를 호출한다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN