다음 코드는 이 HTTP 요청이 OAuth 인가 엔드포인트 요청인가?를 판단하는 조건 객체다.
private final RequestMatcher authorizationEndpointMatcher;
→ HttpServletRequest → true / false 를 반환하는 판별기
생성자
public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
/**
* 이 HTTP 요청이 OAuth 인가 엔드포인트 요청인가?”를 판단하는 조건 객체
*/
private final RequestMatcher authorizationEndpointMatcher;
public OAuth2AuthorizationEndpointFilter(String authorizationEndpointUri) {
/**
* 어떤 HTTP 요청을 /oauth2/authorize 인가 요청으로 볼 것인가?를 정의하는 요청 판별기(RequestMatcher) 즉, 이 Filter 언제
* 동작해야하는지 결정하는 규칙
*/
this.authorizationEndpointMatcher = createDefaultRequestMatcher(authorizationEndpointUri);
}
- 위 코드를 보면 createDefaultRequestMatcher라는 메소드를 통해 무엇을 하게 됨
createDefaultRequestMatcher
- 어떤 HTTP 요청을 OAuth 인가 엔드포인트 요청으로 볼 것인가를 정확하게 정의하는 판별기(factory)다.
Authorization Endpoint에는 서로 다른 2가지 종류의 요청이 들어옴
- 인가 요청 (Authorization Request)
- 동의 제출 요청 (Consent Submission)
→ 하지만 URL은 동일함 그래서 HTTP Method 및 파라미터 조합으로 판별
이 메소드를 분석해보자
private static RequestMatcher createDefaultRequestMatcher(String authorizationEndpointUri) {
/**
* GET /oauth2/authorize
* OAuth 인가 요청의 기본 형태 (RFC 6749 3.1)
*/
RequestMatcher authorizationRequestGetMatcher = PathPatternRequestMatcher.withDefaults()
.matcher(HttpMethod.GET, authorizationEndpointUri);
/**
* POST는 두 가지 의미
* 인가 요청
* 동의 제출
* 파라미터를 봐야함 -> 다음 코드에서 response_type을 보게됨
*/
RequestMatcher authorizationRequestPostMatcher = PathPatternRequestMatcher.withDefaults()
.matcher(HttpMethod.POST, authorizationEndpointUri);
/**
* response_type 파라미터 있는지 검사
* response_type이 있으면 → 인가 요청
* response_type이 없으면 → 동의(consent) 제출 요청
*/
RequestMatcher responseTypeParameterMatcher = (
request) -> request.getParameter(OAuth2ParameterNames.RESPONSE_TYPE) != null;
/**
* 인가 요청 =
* GET /oauth2/authorize
* OR
* POST /oauth2/authorize + response_type 있음
*/
RequestMatcher authorizationRequestMatcher = new OrRequestMatcher(authorizationRequestGetMatcher,
new AndRequestMatcher(authorizationRequestPostMatcher, responseTypeParameterMatcher));
/**
* 동의 제출 =
* POST /oauth2/authorize
* AND response_type 없음
*/
RequestMatcher authorizationConsentMatcher = new AndRequestMatcher(authorizationRequestPostMatcher,
new NegatedRequestMatcher(responseTypeParameterMatcher));
/**
* 최종 결론: 둘 다 인가 엔드포인트 요청이다
* 즉 이 Filter는 최초 인가 요청, 동의 제출 요청
* -> 둘 다 처리한다
*/
return new OrRequestMatcher(authorizationRequestMatcher, authorizationConsentMatcher);
}
우리는 일단 최초 요청만 처리할 거임 그래서 다음과 같이 작성
private static RequestMatcher createDefaultRequestMatcher(String authorizationEndpointUri) {
/**
* GET /oauth2/authorize
* OAuth 인가 요청의 기본 형태 (RFC 6749 3.1)
* POST도 가능
*/
RequestMatcher authorizationRequestGetMatcher = PathPatternRequestMatcher.withDefaults()
.matcher(HttpMethod.GET, authorizationEndpointUri);
RequestMatcher authorizationRequestPostMatcher = PathPatternRequestMatcher.withDefaults()
.matcher(HttpMethod.POST, authorizationEndpointUri);
/**
* 인가 요청 판별
* 다음 중 하나면 Authorization Request
* 1. GET /oauth2/authorize
* 2. POST /oauth2/authorize AND response_type 있음
*/
RequestMatcher authorizationRequestMatcher = new OrRequestMatcher(authorizationRequestGetMatcher,
new AndRequestMatcher(authorizationRequestPostMatcher));
/**
* 이 Filter는 최초 인가 요청
*/
return new OrRequestMatcher(authorizationRequestMatcher);
}
/oauth2/authorize 검사
이는 브라우저 → 인가 서버 즉, 사용자가 로그인 버튼을 누르고 브라우저가 인가 서버에게 요청을 보낸 상황임.
GET /oauth2/authorize?response_type=code&client_id=...
- 여기서부터 OAuth2AuthorizationEndpointFilter가 동작 시작하며
- 밑 코드가 진입점이다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
모든 HTTP 요청은 이 Filter로 들어온다.
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
)
- 밑 코드가 가로채게 됨 /oauth2/authorize가 아니면 → 다음 필터로 넘김
if (!authorizationEndpointMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
- 밑 메소드는 요청의 경로가 /oauth2/authorize 인지, HTTP 메소드가 허용되는지 OAuth 파라미터 조건을 만족하는지를 검사함.
matches
즉, createDefaultRequestMatcher를 탄다.
URL 검사 && HTTP Method 검사
- 밑 코드에서 PathPatternRequestMatcher가 진행함 URL 검사 또한 HTTP 메소드까지 검사
- HttpServletRequest에서
- HTTP Method (GET / POST)
- Request Path (/oauth2/authorize)
를 꺼내서
요청의 path == "/oauth2/authorize" 인가?
요청의 method == GET 인가?
를 직접 비교
RequestMatcher authorizationRequestGetMatcher = PathPatternRequestMatcher.withDefaults()
.matcher(HttpMethod.GET, authorizationEndpointUri);
RequestMatcher authorizationRequestPostMatcher = PathPatternRequestMatcher.withDefaults()
.matcher(HttpMethod.POST, authorizationEndpointUri);
URL 주입
private static final String DEFAULT_AUTHORIZATION_ENDPOINT_URI = "/oauth2/authorize";
public OAuth2AuthorizationEndpointFilter() {
this(DEFAULT_AUTHORIZATION_ENDPOINT_URI);
}
public OAuth2AuthorizationEndpointFilter(String authorizationEndpointUri) {
Assert.hasText(authorizationEndpointUri, "authorizationEndpointUri cannot be empty");
/**
* 어떤 HTTP 요청을 /oauth2/authorize 인가 요청으로 볼 것인가?를 정의하는 요청 판별기(RequestMatcher) 즉, 이 Filter 언제
* 동작해야하는지 결정하는 규칙
*/
this.authorizationEndpointMatcher = createDefaultRequestMatcher(authorizationEndpointUri);
}
- 기본 생성자 == 생성자 체이닝
- 인가 엔드 포인트 URL을 따로 안 주면 기본 값 /oauth2/authorize를 쓰겠다.
public OAuth2AuthorizationEndpointFilter(AuthenticationManager authenticationManager) {
this(authenticationManager, DEFAULT_AUTHORIZATION_ENDPOINT_URI);
}
2. 실제 핵심 생성자 == 생성자 체이닝
public OAuth2AuthorizationEndpointFilter(String authorizationEndpointUri) {
Assert.hasText(authorizationEndpointUri, "authorizationEndpointUri cannot be empty");
/**
* 어떤 HTTP 요청을 /oauth2/authorize 인가 요청으로 볼 것인가?를 정의하는 요청 판별기(RequestMatcher) 즉, 이 Filter 언제
* 동작해야하는지 결정하는 규칙
*/
this.authorizationEndpointMatcher = createDefaultRequestMatcher(authorizationEndpointUri);
}
authorizationEndpointUri == "/oauth2/authorize"
이 값이 그대로 들어가서
PathPatternRequestMatcher.withDefaults()
.matcher(HttpMethod.GET, authorizationEndpointUri);
결과
- 다음과 같이 진행
<http://localhost:8080/oauth2/authorize?client_id=test-client>

- 로그인 페이지에서 비번/아이디 입력 후
2026-02-04T19:00:15.140+09:00 INFO 57683 --- [auth-server] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2026-02-04T19:00:15.141+09:00 INFO 57683 --- [auth-server] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
[AuthzFilter] matched: GET /oauth2/authorize?client_id=test-client
[AuthzFilter] matched: GET /oauth2/authorize?client_id=test-client&continue
https://github.com/whitecy01/oauth2-authorization-server/commits/main/
'RFC > OAuth 2.0' 카테고리의 다른 글
| [OAuth 2.0] OAuth Client 테이블 설계(비밀 클라이언트 기준) (0) | 2026.02.04 |
|---|---|
| [OAuth 2.0] 인메모리 DB 사용자 테스트 (0) | 2026.02.04 |
| [OAuth 2.0] Spring Security 기본 설정(FilterChain + formLogin) (0) | 2026.02.04 |
| [OAuth 2.0] Spring Authorization Server 코드 분석(OAuth2AuthorizationEndpointFilter 클래스) (0) | 2026.02.04 |
| [OAuth 2.0] 인가 엔드포인트 큰 흐름 (0) | 2026.02.04 |