[개인프로젝트] @FeignClient 파라미터 오류
로그인 구현을 구글과 로그인으로 하는 중 각각 로그인 api에 요청을 보내고 응답을 받기 위해 @FeignClient를 이용중이었다.
구글의 경우 로그인 연동 결과로 code까지 잘 받고 접근 토큰 발급 요청하여 accessToken까지 잘 받아서 고객의 이메일과 이름을 잘받았다.
문제상황
네이버의 경우 문제가 생겼다
네이버의 로그인 연동 결과로 code값을 받았지만 접근 토큰 발급 요청에서 Response객체의 필드가 다 null인 상황이 발생한거다..
문제의 상황을 자세히 들여다보자
public class NaverOauth implements Oauth {
@Override
public String getLoginView() {
String reqUrl=NAVER_API_URL+"response_type=code&"
+"client_id="+NAVER_CLIENT_ID+"&state=STATE_STRING&redirect_uri="
+NAVER_REDIRECT_URL;
return reqUrl;
}
}
나의 코드를 일부 발췌해왔다. 일단 Naver로 회원가입 또는 로그인을 하겠다고 하면 해당 네이버 로그인 URL로 이동하게하였다.
그래서 로그인까지 확인하고 code값 까지 받아오는 걸 확인했다
2023-11-22T13:40:45.000+09:00 INFO 2158 --- [nio-8080-exec-3]
c.p.d.m.controller.MemberController : login result = #########
그런데 여기서 앞서 말한 문제 발생
2023-11-22T13:57:44.115+09:00 DEBUG 2233 --- [nio-8080-exec-3]
o.s.c.openfeign.support.SpringEncoder : Writing [NaverRequest(grant_type=authorization_code, client_id=uKrQ_JhavpVwEijIzEIG, client_secret=7Y2QxDEkgP, code=H72NY8HjDAkfLxp32y, state=9kgsGTfH4j7IyAkg)] using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@6f18445b]
2023-11-22T13:57:44.440+09:00 INFO 2233 --- [nio-8080-exec-3]
c.p.d.member.client.naver.NaverOauth : response =NaverResponse(access_token=null, refresh_token=null, token_type=null, expires_in=null)
2023-11-22T13:57:44.533+09:00 ERROR 2233 --- [nio-8080-exec-3]
o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: feign.FeignException$Unauthorized: [401 Unauthorized] during [GET] to [https://openapi.naver.com/v1/nid/me] [NaverClient2#getNaverDetailInfo(Map)]: [{"resultcode":"024","message":"Authentication failed (\uc778\uc99d \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4.)"}]] with root cause
feign.FeignException$Unauthorized: [401 Unauthorized] during
[GET] to [https://openapi.naver.com/v1/nid/me] [NaverClient2#getNaverDetailInfo(Map)]: [{"resultcode":"024","message":"Authentication failed (\uc778\uc99d \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4.)"}]
분명 맨 위줄을 보면 Request객체를 openFeign가 잘 인식했다. 근데 결과적으로 Response필드는 다 Null로 나왓다. 그러다보니 당연히 권한 불가라는 에러가 뜬 것이다.
그래서 직접 url에다가 쿼리 매개변수로 필요한건 붙이고 실행해봤더니 response객체가 원하는 대로 응답이 왔다..
왜일까?? 사실 내가 @FeignClients를 처음 써봐서 나온 에러라고 생각한다.
일단 나의 NaverClient코드를 간단하게 보자면
@FeignClient(name = "naver",url = "${naver.token.url}")
public interface NaverClient {
@GetMapping("/oauth2.0/token")
NaverResponse getNaverToken( NaverRequest naverRequest);
}
이런상태이다. 그래서 나는 "{url}?request 객체 필드들"이렇게 url이 매핑되는줄 알았다. 네이버에서 원하는 url 형태가
https://nid.naver.com/oauth2.0/authorize?
response_type=code&client_id=CLIENT_ID&state=STATE_STRING&redirect_uri=CALLBACK_URL
이었기 때문이다.
그래서 문제점은 뭐냐
json 형식의 데이터 전달
찾아보니 get방식이든 post방식이든 openfeign는 json 형식으로 데이터를 전달한다고 하는 것같다.
거기다가 아까 로그를 보면 "MappingJackson2HttpMessageConverter"를 통해 json형태로 형변환하는 것을 볼 수 있다.
Writing [NaverRequest(grant_type=authorization_code, client_id=uKrQ_JhavpVwEijIzEIG, client_secret=7Y2QxDEkgP, code=H72NY8HjDAkfLxp32y, state=9kgsGTfH4j7IyAkg)] using
[org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@6f18445b]
근데 네이버에서는 get/post방식이 상관없다고 해서 나는 get방식을 택했고 쿼리 매개변수로 데이터를 보내야했다. 하지만 json형식으로 보내다 보니 당연히 권한이 없다고 뜬것이다.
spring cloud docs를 보면 쿼리 매개변수를 위한 어노테이션을 제공한다.
[Feign @QueryMap support]
Spring Cloud OpenFeign provides an equivalent @SpringQueryMap annotation
, which is used to annotate a POJO or Map parameter as a query parameter map.
For example, the Params class defines parameters param1 and param2:
// Params.java
public class Params {
private String param1;
private String param2;
// [Getters and setters omitted for brevity]
}
The following feign client uses the Params class by using the @SpringQueryMap annotation:
@FeignClient("demo")
public interface DemoTemplate {
@GetMapping(path = "/demo")
String demoEndpoint(@SpringQueryMap Params params);
}
If you need more control over the generated query parameter map,
you can implement a custom QueryMapEncoder bean.
그래서 requset 객체 앞에 @SpringQueryMap을 붙였더니...
@FeignClient(name = "naver",url = "${naver.token.url}")
public interface NaverClient {
@GetMapping("/oauth2.0/token")
NaverResponse getNaverToken(@SpringQueryMap NaverRequest naverRequest);
}
바로 성공..
결과적으로 openfeign를 자세히 공부하지 않고 사용했던 나의 잘못이다. 다음 블로그 내용은 openfeign을 자세히 공부하고 적어야겠다.
왜 openfeign를 사용하는지도 찾아봐야지 resttemplate나 다른 방법도 있는데 왜 사용하는지 궁금하기도 하다.