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();
}
...
}
}
AuthorizationFilter는 URL 기반 인가 처리를 담당하는 필터이다.
AuthorizationFilter의 doFilter() 메서드 호출
AuthorizationManager
로 RequestMatcherDelegatingAuthorizationManager 클래스를 사용한다. this.authorizationManager
에 RequestMatcherDelegatingAuthorizationManager
를 주입받은 것을 아래 사진에서 확인할 수 있다.SecurityContextHolderStrategy
로 부터 인증 정보 얻는다. RequestMatcherDelegatingAuthorizationManager의 check() 메서드 호출
RequestMatcherDelegatingAuthorizationManager
는 AuthorizationManager
의 구현체로 RequestMatcher
평가식을 기반으로 평가식에 매치되는 AuthorizationManager
구현클래스에게 권한 심사를 위임한다.
RequestMatcherDelegatingAuthorizationManager
클래스의 mappings 필드는 RequestMatcherEntry
객체로 구성된 리스트이다. RequestMatcherEntry
객체는 requestMatcher
에 경로를 entry
에 AuthenticaionManager
구현체를 담고있다.
3-1. matcher() 메서드를 통해 mappings
의 requestMatcher
와 파라미터로 넘어온 request
의 URI가 매칭되는지 확인한다. 매칭되는 경우 while문을 빠져나간다.
3-2. mapping.getEntry() 로 인가처리를 위임할 AuthorizationManager
구현클래스를 꺼낸다.
3-3. 찾은 AuthorizationManager
구현체에게 인가처리를 위임한다.
찾은 AuthorizationManager 구현체의 check() 메서드가 호출되고 사용자의 권한을 심사한다.
RequestMatcherDelegatingAuthorizationManager
에서 반환받은 AuthorizationDecision
을 AuthorizationFilter
로 반환한다.
AuthorizationFilter
가 AuthorizationDecision
을 반환받았다.
AuthorizationDecision[granted=true]
을 반환받으면 다음 필터를 호출한다.AuthorizationDecision[granted=false]
을 반환받으면 AccessDeniedException 을 던지고 ExceptionTranslationFilter
가 AccessDeniedException()
을 처리한다.RequestMatcherDelegatingAuthorizationManager
의 mappings
필드를 보면 /mypage
요청을 처리할 AuthorizationManager
구현체는 AuthorityAuthorizationManager이다.AuthorityAuthorizationManager
는 /mypage
의 권한정보인 ROLE_USER
를 가지고 있다. AuthoritiesAuthorizationManager
의 check()
메서드를 호출하면서 인증정보와 권한정보를 넘긴다./mypage
에 접근하려면 ROLE_USER
권한을 가져야 하므로 AuthorityAuthorizationDecision[granted=false] 을 반환한다.decision.isGranted()=false
이므로 AccessDeniedException 예외를 던진다.초기화 될 때 스프링 시큐리티가 SecurityConfig
파일 읽어 RequestMatcher
와 AuthorizaionManager
구현체를 생성해 RequestMatcherDelegatingAuthorizationManager
의 mappings
필드 초기화한다.
SecurityConfig
파일에서 USER
를 읽어와AuthorityAuthorizationManager
객체 생성하면서 USER
권한정보를 넘긴다.managerBuilder
에 생성한 MvcRequestMatcher[pattern='/mypage']
와 AuthorityAuthorizationManager[authorities=[ROLE_USER]]
add한다.RequestMatcherDelegatingAuthorizationManager
의 mappings
필드에 managerBuilder
에 저장된 값들이 전달된다.로그인하지 않고 /mypage를 호출했을 경우와 1,2,3번까지는 동일하다.
ROLE_USER권한을 가진 사용자가 로그인하고 /mypage를 호출했을 경우를 알아보자.
/mypage
에는 ROLE_USER
권한을 가진 사용자만 접근할 수 있는데 현재 사용자는 ROLE_USER
권한을 가진다. 따라서 AuthorityAuthorizationDecision[granted=true] 을 반환한다.decision.isGranted()=true
이므로 정상적으로 다음 필터를 호출한다.