일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 백준#boj#12755
- 백준#boj#16932#모양만들기
- 백준#BOJ#2615#오목
- 백준#BOJ#12865#평범한배낭
- 백준#BOJ#1939#중량제한
- 백준#BOJ#8012#한동이는영업사원
- 백준#BOJ#14501#퇴사#브루트포스
- Today
- Total
순간을 성실히, 화려함보단 꾸준함을
@Value 어노테이션이 자꾸 null 이 나와요!!!! 본문
안녕하세요!!!
벌써 글또 4번째 글을 작성하게 되었네요 ㅎㅎ
이번에 작성할 내용은 특별한 내용은 아니고 삽질을 한 경험을 바탕으로 새롭게 얻은 지식을 정리하는 글을 작성하려고 합니다.
바로 @Value
어노테이션을 사용하여 property 값을 주입받는 과정에서 생긴 일입니다.
먼저 @Value
어노테이션은 언제 사용할까요????
Typically used for expression-driven or property-driven dependency injection.
식 또는 속성기반 표현식의 주입성을 받기 위해 사용됩니다.
즉, 스프링 빈들에 정의되어있는 필드에 값을 주입하기 위해서 사용되는 어노테이션 입니다.
public class Test{
@Value("${user.name}")
private String username;
}
대강 이런식으로 사용할 수 있습니다.
더 자세한 내용은 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Value.html 공식문서를 참조하세요!
자 그럼 이제 제가 마주한 문제에 대해서 설명드리도록 하겠습니다.
현재 진행하고 있는 프로젝트에서 ArgumentResolver
를 이용하여 인증이 필요한 서비스들에 대해서 '인증절차' 를 거치도록 구조를 짜놨습니다.
- 로그인 시도
- 로그인 성공 후 access token 부여
- 클라이언트에서 인증이 필요한 서비스에 접근 시도
- ArgumentResolver 에서 access token 검증
이런 플로우로 흘러들어가게 됩니다.
이때, access token 을 생성할 때 고유한 secret key 를 사용하여 token 을 생성하게 됩니다.(이 부분은 jwt token : HS256 알고리즘에 관해서 검색해보세요)
그래서 HS256 암호화 알고리즘으로 생성된 secret key 를 어디선가 고유값으로 저장을 해놔야 할텐데 이를 전 property 파일에 저장을 해놓은 것 입니다.(application-secret.yml 에 저장해 놓았습니다)
spring:
# secret properties
profiles:
include: secret
application.yml 파일입니다.
jwt:
secret: 시크릿 키 값
application-secret.yml 파일입니다.
스프링 프로파일을 이용하여 프로퍼티 파일을 구분지어놨습니다. 스프링 프로파일에 대해서 궁금하신 분들은 아래 공식문서를 참고하세요.
https://docs.spring.io/spring-boot/docs/1.2.0.M1/reference/html/boot-features-profiles.html
public class AuthController {
private final AuthService authService;
@Value("${jwt.secret}")
private String KEY;
~~
}
이렇게 controller 에 @Value
어노테이션을 사용하여 KEY
라는 변수에 property 에 정의한 값을 주입받게 해주었습니다.
ArgumentResolver 도 마찬가지입니다.
@Component
@RequiredArgsConstructor
public class AuthResolver implements HandlerMethodArgumentResolver {
private final SessionJpaRepository sessionJpaRepository;
/**
* TODO:jwt.secret 이 null 인 문제...
* why???
*/
@Value("${jwt.secret}")
private String KEY;
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String jws = webRequest.getHeader("Authorization"); //header 에서 token을 꺼내는 방법
if(jws == null || jws.equals("")){
log.error("servletRequest null");
throw new Unauthorized();
}
byte[] decodedKey = Base64.getDecoder().decode(KEY);
try {
Jws<Claims> claims = Jwts.parserBuilder()
.setSigningKey(decodedKey)
.build()
.parseClaimsJws(jws);
Long userId = claims.getBody().get("id",Long.class);
String email = claims.getBody().get("email",String.class);
String nickname = claims.getBody().get("nickname",String.class);
return UserSession.builder()
.id(userId)
.email(email)
.nickname(nickname)
.build();
} catch (JwtException e) {
throw new Unauthorized();
}
}
}
이 상태에서 로그인 http 요청부터 보내보았습니다.
아무런 문제없이 성공하고 token 값을 리턴 받았습니다.
그리고 ArgumentResolver 에 디버깅 포인터를 걸은 후 인증절차를 거쳐야 할 API 에 요청을 보내보도록 하겠습니다.
띠용?!! KEY
값이 null 인걸 확인할 수 있습니다....대체 왜그런걸까요???
혹시나 ArgumentResolver 를 Bean 으로 등록을 안해놓은 건지 해서 체크도 해보았지만 @Component
어노테이션도 잘 붙여주었고 만약 Bean 등록을 하지 않았더라면 프로젝트를 실행했을 때 컴파일 에러가 발생해야 되는 것이 맞습니다.
답은 바로!!
ArgumentResolver 를 등록하는 과정에 있어서 문제가 있었던 것 이었습니다
현재 제가 작성한 ArgumentResolver 는 HandlerMethodArgumentResolver 라는 인터페이스를 구현한 커스텀 클래스입니다. 따라서 WebMvcConfigurer 를 implements 하는 WebConfig class 에 따로 등록을 해주고 있는데 이때 new ArgumentResolver
라고 새로운 인스턴스를 등록해주었던 것이 원인이었습니다.
그러면 대체 왜 새로운 인스턴스를 등록한 것이 문제였을까요??
생각을 해보면 @Value
어노테이션을 사용하여 값을 주입받을때 반드시 Bean 으로 등록되어있는 객체여야 합니다.
즉, ArgumentResolver를 스프링에게 알려주어 등록을 하려고 할때도 Bean 으로 등록되어있는 ArgumentResolver 여야지만 @Value
어노테이션이 의도대로 동작을 할 수 있다는 것이죠.
그런데 저는 현재 new
연산자를 사용하여 새로운 인스턴스를 생성하여 등록을 해주고 있으니 Bean 객체 아니어서 값을 주입을 받을 수 없는 것입니다.
그럼 어떻게 해결을 해줄 수 있을까요???
간단합니다. ArgumentResolver를 등록할때 Bean 으로 설정한 객체를 등록하면 됩니다.
이렇게 의존성을 주입받은 객체를 등록해주면 됩니다.
더이상 @Value
어노테이션으로 값을 주입한 KEY
값이 null 이 아닌것을 확인할 수 있습니다.
잘못된 내용이 있거나 피드백 해주실 내용이 있으시면 언제라도 말씀해주시면 감사하겠습니다.
출처 : https://wildeveloperetrain.tistory.com/143#comment17192142
'나의 개발 메모장' 카테고리의 다른 글
jvm 시스템 파라미터를 사용하여 배포환경에 따른 active 구분 (0) | 2023.05.06 |
---|---|
HttpClient 를 사용해서 Rest API 웹서비스 구현해보기!!! (0) | 2023.04.18 |
@Transactional 은 mySql 의 auto_increment 값을 롤백시켜주지 않는다고요?! (0) | 2023.03.11 |
[Javascript, Spring]fetch API 로 데이터 서버로 전송하기 (0) | 2023.02.21 |
JPA metamodel must not be empty!!!!!! (0) | 2023.01.18 |