이 외에도 여러가지 일들이 있었지만 대부분 나의 부주의 또는 오랜시간 머리를 굴리다보니 원래 자리로 돌아오지 못한 뇌가 다른 곳에 잠시가서 발생한 일들이었다.
그럼 우여곡절 끝에 위의 오류들을 넘어갈 수 있었는지 확인해보자.
어떻게보면 가장 내가 답답해하고 시간을 오래 끌었던 오류일지도 모른다. 에러 코드는 다음과 같다.
blocked by CORS policy: Request header field access-control-allow-methods is not allowed by Access-Control-Allow-Headers in preflight response.
Cors error를 이야기하기 전에 Oring이라는 용어에 대해서 먼저 알아보자. Origin은 간단하게 설명하면 프로토콜, 주소, 포트번호의 쌍을 이야기한다.
http://localhost:3000
이게 하나의 오리진이라고 볼 수 있다. 여기서 포트번호는 생략해도 무방하다. 생략을 할 경우 HTTP 방식은 80, HTTPS 방식은 443을 이용한다. 이렇게 구성된 Origin이 다르다는 것은 프로토콜, 주소, 포트번호가 다르다는 것을 의미한다.
대부분의 웹 브라우저는 Same Origin Policy(SOP)라는 보안 정책을 준수한다. 사용자의 Origin에서 다른 Origin에 요청한 것을 기본적으로 제한해서 어느정도 해커의 공격에 방어하는 것이다. 하지만 우리가 개발을 하다보면 다른 Origin으로부터의 자원을 불러오고 싶은 경우가 많다. 소셜로그인도 그 중 하나이다. 이런 경우에 사용하기 위해 CORS(Cross Origin Resource Sharing)이 생겨난 것이다. 말 그대로 다른 Origin의 자원을 공유할 수 있도록 표준을 세운 것이다.
Origin에 대해 간단하게 알아보았으니 에러에 대해서 알아보자. 해결하는데 3가지 방법을 시도했던 것 같다.
Access-Control-Allow-Origin 헤더를 설정해주지 않아서 발생한 문제라고 생각했다. 이런 상황에서는 CORS Policy에 의해 요청이 차단된다. 여기서 다른 Origin의 요청이기 때문에 사전요청(Prefilght Request)을 먼저 보낸 것이다. 이런 경우는 헤더를 설정해주면 된다.
headers{
"Access-Control-Allow-Origin": "*"
}
이렇게하면 다른 Origin으로의 요청이 전달된다. 하지만 이렇게 설정할 경우 모든 사이트를 허용하기 때문에 CORS Policy에는 바람직하지 않다고 생각된다.
근데 중요한 점은 이 부분으로 해결이 되지 않았다. 다음으로 넘어가야할 듯 하다.
Proxy를 설정하지 않아서 발생한 것이라 생각했다. 현재 내 프로젝트는 react-app(localhost:3000)과 Spring project(localhost:7777)을 사용하고 있다. FE와 BE의 요청은 spring의 포트번호를 proxy로 설정하여 진행하고 있는 것이다. 그래서 kakao login도 이렇게하면 될 줄 알았다.
근데 proxy가 뭔데?
쉽게 설명하면 서버로 보내는 요청을 대리해서 보내주는 것이다. 서버와 클라이언트의 중계기 역할을 하면서 대리로 통신을 수행하는 것이다. 설정은 2가지 방법이 있다.
// 1.spring 서버와 proxy 설정(경로 : src/setupProxy.js
const {createProxyMiddleware} = require('http-proxy-middleware');
module.exports = function(app){
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:7777',
changeOrigin: true,
})
);
}
// 2.package.json 내부 설정
...생략
"proxy" : "http://localhost:7777"
이렇게 설정하면 서버와의 중계기 역할을하는 Proxy가 설정된 주소로 요청을 전달해준다. 하지만 이 방법도 적용되지 않았다.
진작에 봤어야했다. 아래 단 한마디 때문에 그냥 멍하니 앉아있었다.
"넵, 인가요청(authorize)는 카카오측 페이지 이동 후, 리다이렉트 하므로
브라우저내 XMLHttpRequest를 사용하는 ajax방식으로 사용하시면 안되고 처리하신 것 처럼 a태그로 이동해야합니다."
ajax 방식으로 하면 안된다고 한다. 역시 교과서를 잘보는 친구들이 공부를 잘한다. 공부를 잘하면 시간을 아낄 수 있다. 그렇다. 바보처럼 aixos 통신을 통해 kakao 서버에 계속 인가코드를 달라고 했던 것이다.
그래서 설명해주신 내용대로 a 태그 또는 href 방식을 통해 redirectUri를 지정하여 사용했다. 너무나도 잘되는 것이다.
자세한 내용은 여기를 참고하자. 기본적으로 kakao에서는 token을 조회하는 경우에는 ajax 호출이 가능하지만 인가요청은 불가능하다고 한다.
또한, kakao는 기본적으로 CORS가 열려있으니 별도의 설정은 안해주어도 된다고하니 참고하자.
이렇게 어찌저찌 첫번째 오류는 해결이 되었다. 사실 오류가 아니었다. 그냥 내 실수였다고 하자.🤣
이번엔 API 오류가 아닌 Spring의 properties 값이 객체로 넘어오지 않는 상황이 지속적으로 벌어진 것이다. Spring Legacy로 프로젝트를 진행하다보니 구글링에 나오는 Boot 기반의 방식들이 잘 안먹히는 것 같았다. 이 부분은 크게 어려운 것은 없으니 사용이유와 해결방법만 간단히하고 넘어가도록 하자.
.properties 파일을 사용한 이유는 기본적으로 xml에 property를 지정해줘도 되지만 API를 이용할 경우 보안상 중요한 데이터들이 기본 값으로 포함되어야 하는 경우가 발생한다. 이러한 경우 개인정보가 유출될 수도 있으며, 서비스를 사용할 때 치명적인 정보유출이 될 수도 있다. 그래서 나는 .properties에 별도로 유지를 하고 싶었다. 이 설정 내용을 git에 올리지 않고 싶었기 때문에 사용한 것도 있다.
나같은 경우는 경로를 WEB-INF/config/파일명.properties로 잡아주었다. 그리고 구글링한 설정을 적용해보았다.
<!-- 첫번째 방법 -->
<context:property-placeholder location="classpath:파일명.properties"/>
<!-- 2번째 방법 -->
<context:property-placeholder location="WEB-INF/config/파일명.properties"/>
안된다. 계속 시도해봐도 안된다. Value는 아래와 같이 지정해주었다.
@Value("${kakao.client.id}")
private String client_id;
해당 내용을 로그로 찍어보면 다음과 같은 결과가 나왔다.
log.debug("client_id는 :: " + client_id);
client_id는 :: ${kakao.client_id}
그렇다. 문자열로 인식해서 괄호안의 문자가 그대로 나오는 것이다. 그래서 계속 구글링한 결과 다음과 같은 설정을 해주니 해결되었다.
@PropertySource("/WEB-INF/config/파일명.properties")
@Component
public class Test{
@Value("${kakao.client.id}"
private String client_id;
}
적용하고 싶은 객체 상단에 선언해주고 변수위에 @Value 어노테이션을 붙여주면 정상적으로 작동할 것이다. 이거 때문에도 거의 1시간 이상을 잡아먹었던 것 같다. 이쯤되니 들었던 생각은 여태까지 그냥 DB에 게시판 구성하는 것만 했던 것이 과연 도움이 된 것은 맞는가? 이다. 다른 것은 할 줄 모르는 바보가 된 느낌이었다.
아무튼 이렇게 두번째 오류도 해결하였다.
이 부분은 요청 시 요청 파라미터 값을 잘못 지정해서 났던 문제들이다.
첫번째로 RedirectUri의 경로를 제대로 설정해주지 않았다.
localhost:3000/auth/kakao/callback
위 주소가 처음 API 어플리케이션에 등록했던 RedirectUri였다. 근데 spring은 포트번호가 7777이니 당연히 7777로 받아야하는 줄 알았다.
localhost:7777/auth/kakao/callback
이렇게 2개를 등록해서 요청을 보내고 있었던 것이다. 계속 Bad Request 에러가 났다. 그래서 일단 이 부분을 동일하게 작성해주었다. 근데 계속 에러가 발생한다.
두번째는 body에 authorizationCode가 제대로 넘어오지 않았다. 확인해보니 Controller에서도 해당 값이 null이 나오는 것이다. 이 부분은 FE에서 axios.post 방식으로 요청할 때 Controller에서 파라미터에 @RequestBody 어노테이션을 붙이지 않아서 발생한 것이다.
//Controller
...생략
public ResposneEntity<> handleOauthKakao(@RequestBody KakaoParams params){
}
위와 같이 어노테이션을 명시하여 해결하였다. 기본적으로 Bad Request는 토큰 요청 시 body에 담길 데이터가 비어있는 경우 발생한다고 하니 조심하도록 하자.
로그인 기능을 구현하면서 정말 많은 시행착오를 겪었던 것 같다. 기능을 구현해놓으니 까먹은 부분도 있겠지만 그때그때마다 오류를 정리하는 것이 다음 개발을 위해서도 굉장히 중요하다는 생각을 한다.
마지막으로 오픈API를 사용할 때는 공식문서를 제대로 꼼꼼하게 아주 자~~알 읽는 것이 제일 중요하다는 걸 새삼 깨닫는다. 내 시간을 아낄 수 있는 지름길이니 이걸 보는 분들도 공식문서는 한번이라도 정독하고 기능을 사용하시길 적극 추천한다.
그럼 이만.👊🏽