text/Java

antMatcher? 가 머지

hoonzii 2023. 2. 21. 21:39
반응형

보통 남들이 만들어 놓은 것 중에 자주 쓰이는 것들은 이름부터 잘 지어놔서 함수나 클래스명을 보면 딱 알 수 있는데 그게 아닌 놈을 만났다. antMatcher… 이게 뭔지 궁금해져서 찾아본 결과를 적어놓는다. (대충… 대충…)

 

tl;dr

사용자 요청에 대해 인증, 인가 설정 시 해당 설정에 대한 검사를 수행할 url 경로(regex)를 적는 부분

.antMatchers("/status","/resources/**","/join","/auth/**","/error").permitAll()
.antMatchers("/admin**").hasAnyAuthority("ADMIN")

ant 인 이유는 Apache Ant project에서 따왔다고 한다. url 매칭 시 Ant Pattern을 이용하기 때문.

 

아래는 내가 이번에 조금 알아보고 쓰는 글

 

내가 성의 문지기라고 생각해 보자.

우리 성은 출입가능한 시민에 한해 고유의 신분증을 발급했고, 해당 신분증이 있어야만 성에 들어올 수 있다. 그래서 문 앞에서 성으로 들어오려는 사람의 신분증을 확인하고 성의 신분증이 있다면 OK! 통과, 신분증이 없다면 NO! 들어오지 못하게 막는다.

 

그렇게 경계임무를 하다가 근무교대 시간이 돌아와 이번엔 성문이 아니라 왕의 알현실 앞 문을 지키게 되었다.

왕의 알현실은 성의 주민이라 해도 함부로 들어올 수 없다. 왕이 허락한 주민에 한해 출입을 허가한다. 신분증에는 왕의 허락이 적혀있으므로 알현실에 방문하는 방문객의 신분증을 확인해 적혀있다면 통과~, 없다면 출입을 막는다.

 

이 얘기를 하는 이유는

인증과 인가란?

인증(**Authentication)**이란 위에서 성의 문을 막아 이 성의 주민인지, 아닌지를 판별해 접근을 막는 것을 말한다.

좀 더 한자를 섞어 말해보자면 “사용자의 신원을 검증하는 행위”라고 할 수 있다.

 

인가(**Authorization)**란 검증된 사용자에게 특정 리소스나 기능에 액세스 할 수 있는 권한을 부여하는 프로세스를 말한다. 마치 성의 주민이라도 왕의 알현실은 허락되지 않은 사람은 들어갈 수 없는 것과 같다.

 

 

SpringBoot에서는 이런 인증과 인가를 SecurityConfig의 SecurityFilterChain을 통해 쉽게 구현할 수 있게 해 준다.

SpringBoot SecurityFilterChain

를 얘기하기 전에 알아야 할 선행 단어들이 있다.

  1. servlet filter
  2. delegatingFilterProxy
  3. SecureFilterProxy
  4. SecureFilterChain (finally)

servlet Filter

Client로부터 Server로 요청이 들어오기 전에 서블릿을 거쳐서 필터링하는 것을 서블릿 필터

사용자 요청 수행전 요청 사항에 대한 filter 역할을 하기에 이름을 servlet filter라고 지었음

filter는 chain 형식으로 묶여서 동작하기 때문에 (filter_0번 동작→filter_1번 동작…) FilterChain이라 이름 붙음

delegating Filter Proxy

해당 필터의 구현체로서 저 필터에 들어가는 객체인 delegating Filter Proxy가 존재한다

프록시라고 붙은 이유는 실제 이 Filter는 빈 깡통이고 수행은 다른 객체가 하기 때문인데

Spring container가 사용하고자 하는 filter를 등록시키기 위한 자리를 만든다고 생각하면 조금 이해하기 쉬울 것 같다.

Proxy 이기 때문에 실제 동작을 위한 구현체로 빈 필터의 (Bean Filter) 동작을 수행한다.

(Bean은 Spring IoC 컨테이너가 관리하는 자바 객체로 사용자가 관리할 필요 없이 메모리위에 알아서 떠있고 관리된다.)

delegating Filter Proxy는 실제 역할을 하는 Bean Filter를 받고

Bean Filter를 구현하는 FilterChainProxy (또 프록시? 얘도 깡통)는 실제로 Filter 역할을 수행할 SecurityFilterChain 구현체를 통해 Filter를 사용하게 된다.

SecurityfilterChain 역시 내부의 여러 Filter를 통해 사용자 요청에 대해

인증, 인가를 판별하고 해당 수행 후 결과를 반환(혹은 거부) 동작을 하게 되는데…

이렇게 복잡하게 Proxy 깡통을 만들고 나눠서 동작하게 되는 이유는?

Spring container로 들어오는 요청은 전부 SecurityFilterChain의 필터에서 걸리고 그로 인해 디버깅해 해당 부분만 확인하면 된다.

또한 여러 사용자 요청에 대해 필요한 보안 처리를 나눠서 할 수 있게 되기 때문이다.

(라고 한다. ref https://docs.spring.io/spring-security/reference/5.8/servlet/architecture.html )

 

사용자 요청에 대한 filter를 따로 지정, 해당 Filter 내 인증과 인가에 대한 설정을 할 수 있게 만들었다.

 

requestMatcher

여러 개의 SecurityFilterChain에서 판별하는 HttpSecurity 요청에 대해 개발자가 명시한 url이나 요청에 대해서만 해당 필터를 적용할 수 있게 구현이 되는데 그때 사용하는 게 requestMatcher!

 

그중에서

“finally” AntMatcher

들어오는 요청을 Ant pattern으로 기술, 필터링에 사용하는걸 AntMatcher!

위에 적어놨지만 결론적으로

사용자 요청 중 1) 인증이 됐고, 2) 인가된 요청인지 여부를

판별 및 통과 여부를 결정하는 Filter의 명세사항을 기술하는 함수중 하나라고 보면 될 듯하다.

 

이건 내 코드 예시

@Configuration
public class SpringSecureConfig{

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
	    httpSecurity.csrf().disable()
	            .cors().disable()
	            .authorizeRequests(request -> request
	                    .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
	                    .antMatchers("/status","/resources/**","/join","/auth/**","/error").permitAll()
	                    .antMatchers("/admin**").hasAnyAuthority("ADMIN")
	                    .anyRequest().authenticated())
	            .formLogin(login -> login
	                    .loginPage("/login")
	                    .loginProcessingUrl("/login_process")
	                    .usernameParameter("username")
	                    .passwordParameter("password")
	                    .defaultSuccessUrl("/", true)
	                    .permitAll())
	            .logout(Customizer.withDefaults());
	    return httpSecurity.build();
	}
}

 

reference

반응형