Spring Security 설정을 추가했는데 특정 API만 계속 401이 난 이유
문제 발생
/api/public/**은 인증 없이 열어두고 싶어서 규칙을 추가했는데, 여전히 401 Unauthorized가 반환됐습니다.
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/**").authenticated() // 먼저 선언됨
.requestMatchers("/api/public/**").permitAll() // 이 규칙은 절대 도달 안 함
);원인 분석
Spring Security의 authorizeHttpRequests는 등록된 규칙을 선언된 순서대로 검사하고, 가장 먼저 매치되는 규칙을 적용합니다. /api/**가 /api/public/**보다 먼저 선언되어 있으면, /api/public/health 같은 요청도 /api/** 패턴에 먼저 매치되어 authenticated() 규칙이 적용되고, 그 아래 있는 /api/public/** 규칙은 아예 검사되지도 않습니다.
이건 마치 switch문이나 여러 개의 if-else if가 위에서부터 순서대로 평가되는 것과 같은 원리입니다 — 더 넓은 패턴이 먼저 있으면 더 좁은(구체적인) 패턴이 실행될 기회를 얻지 못합니다.
해결 방안
- 더 구체적인 경로 규칙을 먼저, 더 일반적인 규칙을 나중에 선언합니다.
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll() // 구체적인 규칙 먼저
.requestMatchers("/api/**").authenticated() // 일반적인 규칙 나중
);- 규칙이 많아지면 순서 실수가 반복되기 쉬우므로, 테스트 코드로 각 경로의 실제 접근 가능 여부를 검증해두는 것이 안전합니다 —
@WithMockUser,MockMvc를 활용한 보안 설정 테스트가 표준적인 방법입니다. - Spring Security 자체의
FilterChain순서(여러 개의SecurityFilterChain을 등록하는 경우)도 마찬가지로 순서에 민감합니다 —@Order나securityMatcher()로 어느 체인이 어떤 요청에 적용될지 명확히 분리해야 합니다. - 규칙을 다 작성한 뒤에는 실제로 각 경로에 인증 없이/있이 요청을 보내 예상대로 동작하는지 직접 확인하는 것이 코드만 보고 판단하는 것보다 확실합니다.
공식 문서
- Spring Security Docs: Authorize HttpServletRequests — "the most specific rules should be declared first"를 명시합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.