프로젝트 진행시 개발환경에서 네이버 로그인 api를 구현하였다
구현시 CORS에러를 해결하기 위해 아래와 같이 proxy를 설정하여 진행하였는데,
배포시 설정한 프록시가 적용되지 않는 문제가 생겼다
devServer : {
proxy : {
...
'^/oauth2.0' : {
'target' : 'https://nid.naver.com/',
'changeOringin' : true,
'pathRewrite': { '^/oauth2.0': '/' },
'secure':false
},
'^/v1' : {
'target' : 'https://openapi.naver.com/',
'pathRewrite' : { '^/v1': '/' },
'changeOringin' : true,
'secure':false,
'logLevel' : 'debug'
},
},
port : 9090
...
proxy 설정은 개발환경(Local)에서만 적용되며 배포시에는 적용되지 않는다고 한다!
참고링크 - [TIL] 네이버 로그인 | CORS 에러 해결
- middleware를 설치하여 Proxy server를 생성해 해결하는 방법
- CORS 에러를 프론트에서 해결하여 프론트 단에서 처리
- 콜백 URI를 백엔드 단에서 처리 후 받아온 reponse 데이터를 다시 프론트로 리턴해주는 방법
OkHttp
⇒ REST API, HTTP 통신을 간편하게 구현할 수 있는 Java 라이브러리Okio
⇒OkHttp
를 기반으로 하는 컴팩트한 IO 라이브러리org.json
⇒ Java의 JSON 라이브러리
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>okhttp</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
<version>1.6.0</version>
</dependency>
<!-- json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20211205</version>
</dependency>
import java.util.HashMap;
import java.util.Map;
import org.json.JSONObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
@RestController
@RequestMapping(value = "/api/login")
public class ApiLoginRestController {
// 1. 접근 토큰 발급 요청 : Callback으로 전달받은 정보를 이용하여 접근 토큰을 발급받기
// 콜백페이지(LoginNCallback.vue)에서 호출한다
// 127.0.0.1:8080/fligent/api/login/oauth2.0?clientid=&code=&state=&secret=
@GetMapping(value = "/oauth2.0")
public Map<String, Object> oauth20(
@RequestParam(name="clientid") String clientid,
@RequestParam(name="code") String code,
@RequestParam(name="state") String state,
@RequestParam(name="secret") String secret){
Map<String, Object> retMap = new HashMap<>();
try {
String url = "https://nid.naver.com/oauth2.0/token?"
+ "grant_type=authorization_code&client_id=" + clientid
+ "&client_secret=" + secret
+ "&code=" + code
+ "&state=" + state;
// OkHttp 클라이언트 객체 생성
OkHttpClient client = new OkHttpClient();
// GET 요청 객체 생성
Request.Builder builder = new Request.Builder().url(url).get();
builder.addHeader("X-Naver-Client-Id", clientid);
builder.addHeader("X-Naver-Client-Secret", secret);
Request request = builder.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
// 응답 받아서 처리
ResponseBody body = response.body();
// body.close();
if (body != null) {
String str = body.string();
retMap.put("status", 200);
// retMap.put("result", body.string());
System.out.println("oauth20 의 Response ==> " + str);
// JSON 파싱
JSONObject jobj = new JSONObject(str);
retMap.put("access_token" , jobj.getString("access_token"));
retMap.put("refresh_token" , jobj.getString("refresh_token"));
retMap.put("token_type" , jobj.getString("token_type"));
retMap.put("expires_in" , jobj.getString("expires_in"));
body.close();
}
}
else {
System.err.println("Error Occurred");
}
} catch(Exception e) {
retMap.put("status", -1);
e.printStackTrace();
}
return retMap;
}
// 2. 발급받은 토큰으로 사용자 정보 받아오기
// 127.0.0.1:8080/fligent/api/login/v1?token=&
@GetMapping(value = "/v1")
public Map<String, Object> v1(@RequestParam(name="token") String token) {
Map<String, Object> retMap = new HashMap<>();
Map<String, Object> responseMap = new HashMap<>();
try {
System.out.println("param으로 받아온 access_token => " + token);
String url = "https://openapi.naver.com/v1/nid/me";
// OkHttp 클라이언트 객체 생성
OkHttpClient client = new OkHttpClient();
// GET 요청 객체 생성
Request.Builder builder = new Request.Builder().url(url).get();
builder.addHeader("Authorization", "Bearer " + token);
Request request = builder.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
// 응답 받아서 처리
ResponseBody body = response.body();
if (body != null) {
String str = body.string();
body.close();
System.out.println("Response ==> " + str);
// JSON 파싱
JSONObject jobj = new JSONObject(str);
JSONObject responseObj = jobj.getJSONObject("response");
responseMap.put("birthday" , responseObj.getString("birthday"));
responseMap.put("profile_image" , responseObj.getString("profile_image"));
responseMap.put("birthyear" , responseObj.getString("birthyear"));
responseMap.put("nickname" , responseObj.getString("nickname"));
responseMap.put("mobile" , responseObj.getString("mobile"));
responseMap.put("email" , responseObj.getString("email"));
retMap.put("status", 200);
retMap.put("response" , responseMap);
System.out.println("result ==> "+ responseMap.toString());
}
}
else {
System.err.println("Error Occurred");
}
} catch(Exception e) {
e.printStackTrace();
}
return retMap;
}
}
1-1. Vue 에서 callback uri로 받아온 code와 state를 백엔드로 보낸다
1-2. OkHttp를 이용하여 Callback으로 전달받은 'code' 값을 담아 '접근토큰발급API'를 호출한다
1-3. 받아온 결과를 파싱하여 vue로 결과를 리턴해준다
2-1. OkHttp를 이용하여 발급 받은 접근 토큰을 담아 프로필 정보 조회 API를 호출한다.
2-2. 받아온 결과를 파싱하여 vue로 결과를 리턴해준다
네이버 개발자센터 - 3.4.5 접근 토큰을 이용하여 프로필 API 호출하기
참고링크
안녕하세요~ 같은 내용 배포 연습 중에 있습니다.
혹시 백엔드에서 CORS 처리를 하게 되면, 프론트단의 proxy server는 설정이 불필요할까요?
그게 아니라면 백, 프론트 둘 다 처리 진행되어야 할까요?