Feature/api key issuance#4
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive API key management system, including the core entity, service logic, and a REST controller for CRUD operations. It also implements a custom security filter to authenticate requests via the X-API-KEY header and integrates Flyway for database schema migrations. The code review feedback highlights several areas for optimization and better design: specifically, improving performance by handling usage timestamp updates asynchronously, optimizing database queries by using count methods instead of loading full entity lists, and enhancing encapsulation by avoiding broad Lombok annotations. Additionally, the reviewer suggested more robust exception handling in the security filter and defensive checks for string operations to prevent potential runtime errors.
| ApiKey apiKey = apiKeyRepository.findByHashedKeyAndIsActiveTrue(hashedKey) | ||
| .orElseThrow(() -> new IllegalArgumentException("Invalid or inactive API Key")); | ||
|
|
||
| apiKey.setLastUsedAt(LocalDateTime.now()); |
| public ApiKeyCreateResponse createApiKey(Authentication authentication, ApiKeyCreateRequest request) { | ||
| Member member = getMember(authentication); | ||
|
|
||
| long currentKeysCount = apiKeyRepository.findByMemberId(member.getId()).size(); |
There was a problem hiding this comment.
| public interface ApiKeyRepository extends JpaRepository<ApiKey, Long> { | ||
| Optional<ApiKey> findByHashedKey(String hashedKey); | ||
| Optional<ApiKey> findByHashedKeyAndIsActiveTrue(String hashedKey); | ||
| List<ApiKey> findByMemberId(Long memberId); |
| @Entity | ||
| @Table(name = "api_keys") | ||
| @Getter | ||
| @Setter |
| } catch (Exception e) { | ||
| // Invalid API key - we can either throw error or just let it pass to be caught by security chain | ||
| // Here we just don't set the authentication | ||
| } |
There was a problem hiding this comment.
모든 예외(Exception)를 포괄적으로 잡아 아무런 처리도 하지 않는 것은 예상치 못한 시스템 오류를 숨길 수 있어 위험합니다. 인증 실패(예: IllegalArgumentException)와 시스템 오류를 구분하여 처리하고, 최소한 디버깅을 위한 로그를 남기는 것이 좋습니다.
} catch (IllegalArgumentException e) {
logger.debug("Invalid API key provided: " + e.getMessage());
} catch (Exception e) {
logger.error("Unexpected error during API key authentication", e);
}|
|
||
| String rawKey = "tk-" + UUID.randomUUID().toString().replace("-", ""); | ||
| String hashedKey = HashingUtil.hash(rawKey); | ||
| String displayKey = rawKey.substring(0, 7) + "..." + rawKey.substring(rawKey.length() - 4); |
There was a problem hiding this comment.
현재 키 생성 로직상 안전하지만, substring 인덱스 접근 시 문자열 길이를 먼저 체크하는 것이 방어적 프로그래밍 관점에서 더 안전합니다.
| String displayKey = rawKey.substring(0, 7) + "..." + rawKey.substring(rawKey.length() - 4); | |
| String displayKey = rawKey.length() > 11 ? rawKey.substring(0, 7) + "..." + rawKey.substring(rawKey.length() - 4) : rawKey; |
🚀 개요
외부 서비스 연동 및 API 보안을 위한 API Key 발급 기능과 헤더 기반(X-API-KEY)
인증 시스템을 구현
🛠 작업 내용
추가
컨트롤러 구현
대해 X-API-KEY 헤더를 검증하는 필터 구현 및 SecurityConfig 등록
스크립트 작성 (V2)
시점에만 평문 키 노출