SecurityConfig: Spring Security 6 호환 필터 등록 순서 수정
Build & Deploy to K8s / build-and-deploy (push) Successful in 1m0s
Build & Deploy to K8s / build-and-deploy (push) Successful in 1m0s
기존 코드는 addFilterBefore(AiApi, JwtAuthenticationFilter.class) 가 jwt 등록 전에 호출되어 'JwtAuthenticationFilter does not have a registered order' 예외 발생. Spring Security 6 부터 anchor 는 _이미 등록된_ 필터여야 함. 수정: jwt 를 UsernamePasswordAuthenticationFilter 기준으로 가장 먼저 등록 → JwtAuthenticationFilter.class 가 known map 에 추가됨 → 이후 SubdomainResolver/AiApiKey/TenantConsistency/ForcePw 가 jwt 를 anchor 로 정상 참조. 실행 순서는 동일: SubdomainResolver → AiApiKey → Jwt → TenantConsistency → ForcePw → UsernamePasswordAuthenticationFilter Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -59,21 +59,26 @@ public class SecurityConfig {
|
||||
.requestMatchers("/api/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(new AiApiKeyAuthFilter(aiAgentApiKeyService),
|
||||
JwtAuthenticationFilter.class)
|
||||
// ⚠️ Spring Security 6 부터 addFilterBefore/After 의 anchor 는 _이미 등록된_
|
||||
// 필터여야 함. 따라서 JwtAuthenticationFilter 를 가장 먼저 (Spring 표준
|
||||
// UsernamePasswordAuthenticationFilter 기준으로) 등록한 뒤, 나머지 커스텀
|
||||
// 필터들이 JwtAuthenticationFilter 를 anchor 로 사용한다.
|
||||
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
|
||||
UsernamePasswordAuthenticationFilter.class)
|
||||
// Phase 2 (2026-04-24): 서브도메인 → CompanyResolver → TenantRoutingDataSource 라우팅.
|
||||
// JwtAuthenticationFilter 보다 앞에서 실행되어야 tenant 컨텍스트가 먼저 결정됨.
|
||||
.addFilterBefore(
|
||||
new SubdomainResolverFilter(companyResolver, tenantRoutingDataSource, tenantDbSettings),
|
||||
JwtAuthenticationFilter.class)
|
||||
// AiApi 키 인증 — jwt 앞에서 sk-pipe-* 형식 처리, 매칭되지 않으면 jwt 로 통과.
|
||||
.addFilterBefore(new AiApiKeyAuthFilter(aiAgentApiKeyService),
|
||||
JwtAuthenticationFilter.class)
|
||||
// JwtAuthenticationFilter 뒤 — JWT.company_code 와 서브도메인의 company_code 대조.
|
||||
.addFilterAfter(new TenantConsistencyGuardFilter(jwtTokenProvider),
|
||||
JwtAuthenticationFilter.class)
|
||||
// TenantConsistencyGuardFilter 뒤 — 비번 강제 변경 대기자는 허용 경로만 통과.
|
||||
.addFilterAfter(new ForcePasswordChangeGuardFilter(jwtTokenProvider),
|
||||
TenantConsistencyGuardFilter.class)
|
||||
// Phase 2 (2026-04-24): 서브도메인 → CompanyResolver → TenantRoutingDataSource 라우팅.
|
||||
// JwtAuthenticationFilter 보다 앞에서 실행되어야 tenant 컨텍스트가 먼저 결정됨.
|
||||
.addFilterBefore(
|
||||
new SubdomainResolverFilter(companyResolver, tenantRoutingDataSource, tenantDbSettings),
|
||||
JwtAuthenticationFilter.class);
|
||||
TenantConsistencyGuardFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user