[BE-08] PartnerApiKeyAuthenticationFilter (API Key → 연동 User principal 주입 + 감사 트리거)
작업 내용 (설계 의도)
변경 사항
근거 TDD: ../TDD.md “Sequence Diagram”·ADR-007/008/009. McpTokenAuthenticationFilter 패턴 답습. SecurityConfig 수정은 BE-10 (이 티켓은 필터 클래스만 — Single Writer).
infrastructure/security/PartnerApiKeyAuthenticationFilter.kt(OncePerRequestFilter):Authorization: Bearer partner_<keyId>_<random>파싱.partner_prefix 아니면 pass-through.partnerDomainService.authenticate(keyId, plainKey)→ 실패 시 401(무효/REVOKED)·403(SUSPENDED) JSON 응답, 체인 중단.- 성공 시
userDomainService.getRolesForUser(linkedUserId)로 roles 로딩 →UserPrincipal(id=linkedUserId, email, roles)+ROLE_*authorities로SecurityContext주입(기존UserPrincipal재사용). partnerApiKey.recordUsage()반영(lastUsedAt).filterChain.doFilter후 응답 status·latency로PartnerActivityRecorder.record(...)호출(@Async, BE-04 구현).
partner.auth.enabled플래그는 SecurityConfig 등록 시 게이트(BE-10). 필터 자체는 prefix 미매칭 pass-through라 기존 트래픽 무영향.
롤백: 플래그 OFF(BE-10 등록 게이트) 시 필터 미등록 → 파트너 인증 경로 휴면.
의존
- BE-01, BE-02, BE-05
다이어그램
처리 흐름
sequenceDiagram participant C as Client participant F as PartnerApiKeyFilter participant P as PartnerDomainService participant U as UserDomainService(기존) C->>F: Bearer partner_<id>_<rand> F->>P: authenticate(keyId, plainKey) P-->>F: (partnerId, linkedUserId) F->>U: getRolesForUser(linkedUserId) F->>F: inject SecurityContext(UserPrincipal) F->>F: doFilter → record(@Async)
테스트 케이스
- 유효 ACTIVE 키 요청 시 연동 User principal(roles 포함)이 SecurityContext에 주입되고 체인이 진행된다.
- partner_ prefix가 아닌 Authorization은 pass-through한다(JWT 경로 무영향).
- REVOKED 키 요청은 401 JSON을 반환하고 체인을 중단한다.
- SUSPENDED 파트너 키 요청은 403을 반환한다.
- hash 불일치 키는 401을 반환한다.
- 체인 완료 후 PartnerActivityRecorder.record가 응답 status·latency로 호출된다.
- 감사 record가 실패해도 요청 응답에는 영향이 없다.