본문 바로가기
프로젝트

블로그 - 다중 SecurityFilterChain 우선 순위 : 트러플 슈팅

by ernest45 2025. 4. 18.

 

FilterChainProxy가 불러진다

 

 

 

 

블로그 프로젝트 중 filterChain을 요청에 따라 각 각의 filterChain을 활용하고 싶었다.

두 개의 필터체인을 등록하고 받는 requestMatcher만 잘 활용해 url만 따로 지정한다면 내가 원하는 동작으로

이루어질 줄 알았으나, 403이 떠서 아예 원하는 체인 자체는 인증을 통과하지 못하는 이슈!

 

 

 

 

 

1. 요청마다  filterChain을 다르게 타고 싶다면?

 

 

기본적으로 하나의 filterChain으로 사용해왔는데,

이번 프로젝트의 경우

나는 OAuth2는 custom된 filterChain을 통해 일반 로그인의 필터를 거치지 않았으면 했다.

 

즉 일반로그인필터와 oauth로그인 필터를 구분해서 사용하고 싶다!

 

 

도입 이유  -

그 이유는 요청마다 filter를 다르게 이용한다면

보안 정책의 분리와 관리 용이하고, 확장성에 장점이 있을 것이라고 판단했다.

 

 

 

 

그래서 어떤 요청마다 filterChain을 다르게 타고 싶다면?

 

다른 여러 개의 필터체인을 등록해 원하는 요청에 맞게 필터체인을 이용하면 될 것이다.

 

간단하게 등록해보자

 

 

간단한 securityConfig 파일이다.

 

@Bean으로 둘 다 등록을 해둔 상태이다.

 

 

(2025 3월 추가 -- 호출 과정은 포스트를 참고)

사용자 요청부터 스프링 시큐리티까지 feat)OAuth2

 

사용자 요청부터 스프링 시큐리티까지 feat)OAuth2

스프링 시큐리티 6 기준! 실제 스프링 시큐리티를 만지면서 너무 어렵고 깊이있게 파고들고 싶어서 좀 더 알아보는 흐름을 갖고 싶어서 써보겠다 실제 유저가 스프링에 요청을 보내는 순간으로

ernest45.tistory.com

 

 

FliterChainProxy 클래스가 요청을 가로채고

 

getFilters의 메서드에서 breakPoint를 걸면 몇 개의 FilterChain이 등록 됐는지 알 수 있다.

 

 

 

FliterChainProxy - getFilters

 

 

 

현재 filterChains의 size가 2임으로 2개가 등록된 걸 알 수 있다.

 

 

 

2. 그렇다면  filterChainProxy는 어떤 기준으로  FilterChain을 고를까?

 

 

멀티 SecurityFilterChain 중 하나 선택

 

FilterChainProxy는 N개의 SecurityFilterChain 중 하나를 선택해서 요청을 전달한다

 

    • 기준

1. 등록 인덱스

2. 필터 체인에 대한 RequestMatcher 값이 일치하는지 확인 (인가 설정이 아님, 아래에서 설명)

 

 

 

먼저 등록된 인덱스로 우선 작용한다.

첫번 째 등록된 인덱스의 필터체인의 requestMatcher값(매핑 url) 이 없다면

다음 등록된 필터체인으로 탐색하는 식의 방식이다.

 

 

 

 

 

문제 1

 

멀티 SecurityFilterChain 설정시 N개의 SecurityFilterChain 모두 “/**” 경로에서 매핑된다

 

 

 

가정 - 각 각 필터체인을 등록하고, 서로 다른 URL을 받는다.

 

 

 

 

1번 filterChain은 “/user”

2번 filterChain“/admin” 경로에 대해서 permitAll() 설정

user 200 , admin 403

 

user로 보내면 1번 filterChain으로 매핑이 완료

 

이후 “/admin” 경로로 요청을 보내면 별다른 인증 과정 없이 

2번 filterChain으로 매핑될 것이라 예상하지만

but 403이 발생

 

이유는

filterChain1이 filterChain2 보다 **먼저** 등록되어 있고 

 

SecurityFilterChain에 특별한 경로 설정을 하지 않으면, HttpSecurity는 모든 경로 (/**)에 대한 보안 설정을 적용함

 

 

 

 

즉 요청이 “/**” 경로로 반응해 filterChain1 전달되었고

filterChain1 내부의 인가 설정에서는 “/admin” 대한 설정이 없기 때문에 거부!

 

 

 

 

해결1  - securityMatcher 사용

 

 

 

 

securityMatchers로 어떤 요청 URL에 대해 필터 체인을 작동할 지 선정

이 경우 /user의 경로에 대해서만 이 SecurityFilterChain이 작동

 

즉, 이 설정은 /user 경로만 필터링 대상이 되고, /admin은 이 chain에서 작동 x

 

 

*주의*

이 설정은 인가 설정이 아닌, filterChain에 대한 경로 설정이라고 보면 된다.

Chain 자체에 대한 인가 설정이라고 할 수 있다!

 

 

 

 

마찬가지로 /admin 요청을 받고 있는 필터 체인도 적용해보자.

 

@Bean
public SecurityFilterChain FilterChain1(HttpSecurity http) throws Exception {

    http
            .securityMatchers((auth) -> auth.requestMatchers("/admin"));

    http
            .authorizeHttpRequests((auth) -> auth
                    .requestMatchers("/admin").permitAll());


    return http.build();
}

 

 

 

 

결과 -

 

 

해결2 -@Order 사용

 

N개의 SecurityFilterChain을 등록 한 뒤 등록되는 순서를 직접 선정하고 싶은 경우 @Order() 어노테이션에 값을 명시할 수 있다.

 

그치만

이 경우에는 순서를 지정해서 탐색할 뿐이라 원하지 않는 상황에 마주칠 확률이 있을 것 같아서

명시적으로 securityMatchers을 사용 하는 게 더 좋을 것 같다!

 

 

 

 

마무리

 

 

filterChain의 경우 설정만 하고 다르게만 호출한다면내 생각대로 이루어질 것 같았지만, 내부적으로는 내가 이해못하는

동작들이 있었다.

어떤 일이든 간단하게 생각하지말고 명시적으로 선언해줘야한다고 생각한다.

 

컴퓨터는 똑똑하지만 멍청하다. 내가 좀 더 꼼꼼하게 명령해주마

 

 

 

https://dololak.tistory.com/599

https://www.devyummi.com/page?id=66969cd412b680b5762f67d5