1. Interceptor를 이용한 API 로깅 클래스 만들기
1. [문제 인식 및 정의]
UserRole eum의 ADMIN 값이 아닌 유저가 관리자 권한에 접근을 logging하고 차단하기 위해 Interceptor를 추가했다
JwtFilter.java 파일에 ADMIN 이 아닌 권한의 유저가 접근할 경우에 대한 로깅과 오류 throw에 대해 중복 로직이 있었다
2. [해결 방안]
2-1. [의사결정 과정]
관리자가 아닌 사용자가 관리자 권한 메서드인 댓글 삭제와 권한 변경 end point에 접근할 경우에 대해 로그 작성과 접근 차단이 모두 중요하다고 판단했다
` 또한 관리자가 아닌 사용자에 대해 접근을 제한하고 예외를 발생시키는 동작은 JwtFilter에 더 적합하다고 생각했다
2-2. [해결 과정]
AdminInterceptor.java의 에러 발생 부분을 삭제 하고 로깅 기능에 책임을 다하도록 했다
JwtFilter에서 예외를 발생시키고 에러메시지를 전송하도록 해 필터링 기능에 책임을 다하도록 했다
3. [해결 완료]
3-1. [회고]
각 클래스의 책임, 역할에 대해 한번 더 생각해보는 계기가 되었다
내가 작성한 코드가 아닌 코드에 대해 파악하기 어려운만큼 더 자세히 살펴봐야함을 깨달았다
3-2. [전후 데이터 비교]
중복 로직을 삭제함으로써 코드를 보다 깔끔하게 할 수 있어 큰 차이는 없지만 이점을 가진 것 같다
2. @Auth custom annotaion 활용하기
1. [문제 인식 및 정의]
@Auth 라는 사용자 정의 어노테이션을 찾게 되었다
쓰임이 많았는데, AuthUser라는 정보 전달 클래스와 함께 인증/인가가 된 사용자 정보를 전달하고 있었다
인증, 인가는 HandlerMethodArgumentResolver를 구현하는 클래스에 의해 doFilter() 메소드로 구현할 수 있다는 것을 알게 되었다
2. [해결 방안]
2-1. [의사결정 과정]
AuthUserArgumentResolver 의 Bean을 등록해 의존성을 주입하고자 했다
clone 받은 메서드를 최대한 활용해 코드를 구현하고자 했고, 중복되는 메서드가 없도록 확인했다
2-2. [해결 과정]
@Component 사용해서 AuthUserArgumentresolver Bean으로 등록 했으며 의존성을 주입했다
기존에 있던 doFilter() 메서드 수정해 @Auth 활용해 인증/인가를 검증했다
JwtUtil의 substringTokren() 메서드를 삭제하고 Token 검증 및 토큰 구하는 기능을 JwtFilter의 resolveToken() 메서드로 옮겨 검증 후 즉시 에러를 throw하게 했다
JwtUtil의 extractClaims() 메소드를 활용했다
AuthUserArgumentresolver 클래스 내 쓰임이 없던 resolveArgument() 메소드를 활용했다
3. [해결 완료]
3-1. [회고]
어노테이션을 사용자 정의하고 활용할 수 있는 범위가 넓다는 것을 알게 되었다
필드, 타입, 파라미터등 다양한 범위에 어노테이션을 사용할 수 있고 또한 범위를 지정할 수 있다는 것을 확인할 수 있었다
인증 및 인가, 정보 전달에 활용하는 역할에 적합함을 알 수 있었다
3-2. [전후 데이터 비교]
위에 언급한 쓰임이 없던 클래스와 메소드를 활용하게 되었다
3. application.properties 파일과 JWT secretKey 오류
1. [문제 인식 및 정의]
1. properties 파일이 존재하지 않아 DB와 application이 연결되지 않아 실행되지 않았다
2. properties 내부에 JwtUtil.java 파일에 기재된 알고리즘과 일치하는 JWT secretkey 설정이 없었다
기재된 알고리즘: SignatureAlgorithm.HS256
2. [해결 방안]
2-1. [의사결정 과정]
아래의 에러 메세지가 로그로 남으며 스프링 어플리케이션의 실행이 되지 않았다
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jwt.secret.key' in value "${jwt.secret.key}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180) ~[spring-core-6.1.12.jar:6.1.12]
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) ~[spring-core-6.1.12.jar:6.1.12]
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239) ~[spring-core-6.1.12.jar:6.1.12]
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210) ~[spring-core-6.1.12.jar:6.1.12]
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:200) ~[spring-context-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:964) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1374) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:785) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:768) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) ~[spring-beans-6.1.12.jar:6.1.12]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:509) ~[spring-beans-6.1.12.jar:6.1.12]
... 74 common frames omitted"
에러 메시지를 보아 프로퍼티스 파일과 내부의 시크릿 키값이 설정되지 않아서 발생하는 오류라고 인식했다
아래 사이트를 이용하여 기재되어있는 알고리즘을 사용해 시크릿 키값을 구했다
https://8gwifi.org/jwsgen.jsp#google_vignette
application.properties 파일에 jwt.secret.key='키값'을 입력했다
그러나 .JwtUtils.java 파일의 아래 코드에 해당하는 secretKey값의 @Value 어노테이션이 프로퍼티스 파일의 값을 인식하지 못했다
@Value("${jwt.secret.key}")
private String secretKey;
2-2. [해결 과정]
여러 방법을 찾아보던 중 한 가지의 방법을 생각해낼 수 있었는데, secreKey 값의 어노테이션에 @Value("${jwt.secret.key:'키값'}")을 직접 넣어주는 방법이었다
어플리케이션을 실행할 수 있었지만 해당방법에는 치명적인 단점이 있었는데, 보안키 값이 github 에 노출이 된다는 것이었다
따라서 그 외의 다른 방법을 찾게 되었는데 바로 InteliJ 환경변수에 프로퍼티의 secretKey값을 넣어주는 것이었다
프로퍼티 파일에 jwt.secret.key=${jwt_secret_key} 다음과 같이 설정하고 InteliJ Edit Connfigurations 설정에서 Environment Variables의 새로운 값으로 jwt_secret_key 값을 추가해 해결했다
이후 정상적으로 프로그램을 실행할 수 있었다
3. [해결 완료]
3-1. [회고]
막연히 어떻게 해결할까 생각하기보다 서치하고 여러 방법을 시도하면서 문제를 해결할 수 있었다
이번 경험을 통해 InteliJ의 환경변수 기능을 알게 되었고 환경변수를 설정할 수 있게 되었다
3-2. [전후 데이터 비교]
코드에 변화 없이 키값을 노출하지 않으면서 어플리케이션 상의 오류를 해결할 수 있었다
'[Kotlin&Spring] 5기 내일배움캠프' 카테고리의 다른 글
| [Kotlin&Spring] 5기 어플리케이션 내의 동시성(Concurrency) (0) | 2025.03.11 |
|---|---|
| [Kotlin&Spring] 5기 아웃소싱 프로젝트 트러블슈팅 - AOP 에러 해결 (1) | 2025.03.07 |
| [Kotlin&Spring] 5기 스프링 3.4 버전 MockitoBean Annotation (0) | 2025.02.26 |
| [Kotlin&Spring] 5기 JPA 연관 관계 매핑과 N+1 문제 (1) | 2025.02.24 |
| [Kotlin&Spring] 5기 운영체제에서 출발한 동기화 문제와 DB 로딩 전략 (0) | 2025.02.13 |