저번 글에서는 기본 바탕을 설명했으니 이번엔 직접 구현해보려고 한다. 구현하면서 필요한 이해를 전에 작성했으니 기왕이면 이전 글 먼저 참고하고 오길 바란다. 이번엔 코드 설명이 대부분일거다.(엄청 길다. 화이팅)
우선적으로 oauth 기능을 사용하려면 해당 플랫폼에 신청을 해야한다. 그래야 client id, client secret 등을 받아오고 redirect URL을 등록할 수 있다.
아래 링크로 들어가 환경 구성을 해보자.
https://console.cloud.google.com/apis/dashboard
원래는 직접 차례를 설명하고 싶었는데 프로젝트를 수행하면서 작성하는 것이 아니라 다 끝나고 기억을 더듬어가며 작성하는거라 방법을 잊어버렸다..아래 링크로 환경구성해나가면 될것이다.
구글 로그인 api 환경설정 참고 티스토리
환경구성 서칭하다보면 여러 설명들이 있는데 꼭 작성해야하는 것들이 있다. 다른건 몰라도 이것들은 꼭 작성해야 나중에 원하는 데이터를 가져올 수 있으니 필수 준비물이라 생각하고 주의하도록.
저번 글에서 얘기한 ouath 과정과 만들어 둔 flowchart를 참고해서 코드를 작성해보자.
핵심은 GoogleOAuth다. 필요한 모든 정보와 메서드를 안에다가 구현해놓고 controller나 service에서 호출하도록 하는 것이다. 그리고 우리가 위에서 준비한 준비물들은 application.properties에 작성해두어 @Value를 통해 가져올 수 있게 한다.
#google login api
google.auth.token.url=https://oauth2.googleapis.com/token
google.login.url=https://accounts.google.com
google.redirect.uri=http://localhost:9090/google/login/callback
google.userinfo.request.url=https://www.googleapis.com/oauth2/v1/userinfo
google.auth.scope=profile,email,openid
google.client.id=[구글에서 발급한 client id 복사 붙여넣기]
google.secret=[구글에서 발급한 client secret 복사 붙여넣기]
GoogleOAuth에서 값을 받아올 수 있도록 먼저 준비물 세팅을 해놓자.
application.properties에서 설정한 값들을 위 사진과 같이 GoogleOAuth안에서 호출할 수 있도록 설정한 것이다. 이렇게 하면 이후에 메서드 안에서 값들을 호출 할 때 쉽게 찾아올 수 있다.
view에서 구글 버튼을 누르면 "/google" path로 이동하게 설정해두었다. 그러면 33번줄을 실행하게 될텐데, 이는 클라이언트가 서비스를 요청하여 로그인을 요청하는 과정과 같다.
자세히 뜯어보면 위 사진과 같다. http message로 보낼 정보들을 String형식으로 정리하여 return해주는 것이다. 이를 controller에서 sendRedirect메서드를 통해 로그인 페이지를 돌려받는다.
로그인을 하거나, 원래 구글 계정이 존재하여 프로필을 선택하면 구글은 Authorization code를 발급해준다. 그리고 우리가 설정해둔 RedirectURL로 리다이렉트 된다. 우리는 redirect URL에 우리가 받은 code 정보를 넘겨주어야한다.
컨트롤러에서 redirectURL을 처리할 때를 구현한 것이다. 최대한 controller에서는 복잡한 처리를 하지 않고 service와 ouath클래스에서 이를 해결하도록 설정했다. 위에서 넘겨받은 code를 signInByOAuth(code)메서드를 통해 이전에 사용하던 dto의 형식으로 데이터를 받아올 수 있게 했다. -> google, kakao 로그인도 이전 프로젝트 로그인과 형식을 같이 해주기 위함이다.
(+ 아직 jwt는 사용하지 않고 session을 통해 접근을 제한해주었다.)
앞에서 로그인을 통해 클라이언트의 몫은 다 끝났다. 그렇다면 service와 플랫폼에서 클라이언트가 준 코드를 통해 원하는 데이터를 주고받으면 된다. 이는 해당 메서드를 통해 구현할 예정이다.
1. 코드를 request를 통해 보내 token 정보를 가진 response를 받아온다.
2. token 정보를 가지는 response를 dto에 매핑하여 저장한다.
3. token 정보를 가지는 dto를 request를 통해 원하는 회원 정보를 response에 담아온다.
4. 담아온 정보를 dto에 매핑하여 담도록한다.
getGoogleUserInfoDto()메서드의 과정을 순서대로 적은 것이다. 위 과정 모두 GoogleOAuth.class의 메서드로 구현해놓을 것이다. 우리는 service클래스에서 getGoogleUserInfoDto()를 호출하면 GoogleUserInfoDto를 가져올 수 있게 되는 것이다.
이 메서드는 singInByOAuth()메서드에서 호출 될 것이다.
따라서 controller에서는 singInByOAuth(code)를 통해 위와 같은 과정을 진행하는 것이다.
이제 원하는 response를 받아오기 위해서는 restTemplate을 사용할 것이다. (restTemplate에 대한 얘기는 다음글에서 자세히 작성할 예정이다.)
restTemplate을 통해 parameter과 url을 던져 받아온 response는 token의 정보를 가지고 있을 것이다. 이는 dto를 통해 매핑한다.
if문에서는 제대로 response를 가져왔을 때 responseEntity를 반환하도록 한 것이다.
objectmapper를 통해 우리가 가져온 response의 값들을 GoogleOAuthTokenDto에 저장할 수 있다.
헤더에 dto안에 있는 access_token의 정보를 담아 던진다. 이 또한 requestAccessToken메서드와 마찬가지로 restTemplate으로 response Entity를 받아온다.
마지막 이 메서드를 통해 원하는 회원의 정보를 가져올 수 있게 되었다. 우리는 이 dto를 통해 DB에 회원의 정보를 저장하고, 조회할 것이다. 물론 저장과 조회는 service클래스에서 수행한다.
getGoogleUserInfoDto메서드를 통해 받아온 정보를 조건문을 통해 DB에 존재하는 회원인지 확인한다. 만약 존재하지 않는 정보라면 googleUser안의 정보로 회원가입을 해준다. password는 Member Entity에서 nullable일 수 없도록 설정하였기 때문에 임의로 설정해준다. 조회할 때도 임의의 password를 통해 정보를 가져온다.(카카오의 경우 admin_token을 주는데, 이를 password에 사용하곤한다.)
단순히 Member Entity의 정보를 MemberInfoDto에 담는 메서드이다.
조금 생뚱맞아보이지만 위에서 restTemplate을 호출하고 사용하기 위해 필요한 부분이다. http통신을 위해 restTemplate을 빈에 등록하고 호출할 때마다 위의 세팅에 따라 사용가능한 것이다. 이에 대해서는 다음글에 더 자세하게 다룰 예정이다.
비슷한 자료들이 몇개 있을텐데(이전글에 참고자료로도 올렸다.)굳이 직접 다시 글을 만든 이유가 있다. 분명 비슷한 글, 구조인데도 하나로는 이해가 안됐는데, 비교하면서 보니까 이해하는데 도움이 되는 것 같았다. 이번 글도 비교대상이 되면 좋을 듯 싶어서 열심히 캡쳐했다.
코드 리뷰 중에 문제점이 조금씩 보인다. 이번 글에서는 코드의 흐름을 참고하면 좋을 것 같다. service에서도 조회기능이랑 저장 기능은 따로 하는게 좋아보이고.. restTemplate과 같은 http 서버 통신 방식도 참고자료들로부터 똑같이 카피한것이기 때문에 "대략적으로 이런식으로 사용되는구나" 이해한 수준이다.
다음글에는 주로 restTemplate을 조사해볼 예정인데, 체감상으로는 굉장히 편리하다. 로그인 api를 사용하기 전에는 영화 정보 api를 사용했었는데, 이때는 http connection을 사용했었다. 그때보다 꽤나 코드가 줄어들고 직관적이라는 느낌이 든다. 그리고 kakao도 google과 같은 방식으로 추가해봤는데, 확장에도 유용한것 같더라.