이번에 소셜로그인을 진행하면서 , 그간 한두번 해봤던 소셜로그인을 다시 해보았다.
항상 구글검색으로 나온 코드를 맞는지 틀리는지도 모르고, 대충 복붙하여 오류범벅으로 사용하곤 했는데,
API를 여러번 사용하며 Http로 데이터를 주고 받는 것에 익숙해지니, 정말로 쉽게 느껴졌다.
소셜로그인 제공업체의 API명세를 보며 직접 코드를 짜다보니,
예전에 복붙하던 코드에는 내 프로젝트엔 필요없는, 쓸데없는 게 많았구나 하고 느끼기도 했고,
이렇게 간단한게 왜 그 당시에는 그렇게 어려웠을까... 하고 생각이 났다.
물론 아직도 한참 부족하지만, 전보다는 성장함을 느끼게 해준 부분이라 참 뿌듯했다.
일단, OAuth란 무엇일까?
각자의 경험으로 생각해봐도 소셜로그인, 즉 카카오나 네이버, 구글로그인 등이 웹에서 보인지는
2022년 기준으로도 그리 오래되지 않았다.
OAuth는 2010년에 발표되었고, 그 후구조적인 문제점을 해결한 OAuth2.0이 발표되어 많이 사용되고 있다.
OAuth가 등장하기 전에는 A사이트에서 B사이트의 리소스를 가져오기 위해서는
A사이트에서 ID와 Password를 직접 입력받고, 저장하여 필요할 때마다 불러와서 사용을 해야했다.
내 사이트에서 카카오로그인을 하기 위해서는 카카오ID와 비밀번호를 직접 내 사이트에 입력을 해야했다는 것 이다.
조금만 봐도, 당연히 말이 안되는 이 방식은 다음과 같은 문제가 발생한다
- 사용자 : A 사이트에 B사이트의 ID와 Password를 넘겨주는 것에 대해 신뢰할 수 없다.
- A 사이트 : ID와 Password를 받았기 때문에 보안 문제가 생기는 경우 모든 책임을 져야한다.
- B 사이트 : A 사이트를 신뢰할 수 없다.
상식적으로 생각해봐도 발생 할 수 있는 문제이다.
이것을 해결하기 위한 OAuth2 인증방식이다.
그렇다. 일단 처음 표만 보면 이게 대체 무슨소리인지 모르겠다.
하지만 간단하다.
1. 권한부여 code 요청
2. code를 이용해서 Access Token을 발급받는다.
3, Acess Token으로 API를 호출해서 필요한 값(사용자 정보) 을 받는다.
결국 3번의 호출을 하면 되는 것이다.
code -> Access Token -> API 요청
구현한 코드로 직접 따라가 보겠다.
@GetMapping("/naver")
public ModelAndView logion(String code,HttpServletRequest request)throws Exception{
HttpSession session = request.getSession();
RestTemplate restTemplate = new RestTemplate();
ObjectMapper mapper = new ObjectMapper();
//Access Token받기
HttpHeaders headersAccess = new HttpHeaders();
headersAccess.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_id","발급받은 REST API 키");
params.add("redirect_uri","리다이렉트할 url");
params.add("code", code);
HttpEntity<MultiValueMap<String, String>> kakaoRequest = new HttpEntity<>(params, headersAccess);
ResponseEntity<String> response = restTemplate.exchange("https://kauth.kakao.com/oauth/token"
, HttpMethod.POST, kakaoRequest, String.class);
NaverLoginVO naverVO = mapper.readValue(response.getBody(), NaverLoginVO.class);
//사용자정보 가져오기
HttpHeaders headersInfo = new HttpHeaders();
headersInfo.add("Authorization", "Bearer " + naverVO.getAccess_token());
headersInfo.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
HttpEntity<HttpHeaders> kakaoInfo = new HttpEntity<>(headersInfo);
ResponseEntity<String> infoResponse = restTemplate.exchange("https://kapi.kakao.com/v2/user/me",
HttpMethod.POST, kakaoInfo , String.class);
NaverInfoVO infoVO = mapper.readValue(infoResponse.getBody(), NaverInfoVO.class);
String nickname = String.valueOf(infoVO.getProperties().get("nickname"));
String id = String.valueOf(infoVO.getId());
Member member = new Member();
member.setId(id);
if(memberService.idCheck(member) == 0) {
member.setName(nickname);
memberService.joinInsert(member);
Member login = memberService.naverLogin(member);
session.setAttribute("member", login);
}else {
Member login = memberService.naverLogin(member);
session.setAttribute("member", login);
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:/social/social-view");
return modelAndView;
}
일단 카카오 key발급같은 부분은 구글검색을 통해 너무너무 많이 자료가 있으니 생략하도록 하겠다.
1. 권한부여 code 요청
제일 위부터 보면 먼저 매개변수로 code를 받는다.
1번인 인가코드를 받는 것은 프론트에서 시작한다.
카카오 로그인 문서에 이렇게 친절하게 다 나와있다.
<a href="https://kauth.kakao.com/oauth/authorize?client_id=발급받은키&redirect_uri=리다이렉트 할곳&response_type=code" >카카오로그인</a>
GET 방식이니, 따로 컨트롤러 호출을 할 필요 없이 바로 링크에 파라미터를 담아서 API를 호출해주자.
이렇게 접속하면 카카오로그인 창이 뜬다.
여기서 로그인에 성공하면 리다이렉트 주소인 /naver로 매핑이되어 컨트롤러가 호출된다.
매개변수로 code를 받아주면 되겠다.
2.Access Token 받기
이제 code를 받았으니 이걸로 Access Token을 받아보자.
post로 요청을 보내고, access 토큰을 응답받으면 되겠다.
RestTemplate restTemplate = new RestTemplate();
ObjectMapper mapper = new ObjectMapper();
//Access Token받기
HttpHeaders headersAccess = new HttpHeaders();
headersAccess.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_id","발급받은 REST API 키");
params.add("redirect_uri","리다이렉트할 url");
params.add("code", code);
HttpEntity<MultiValueMap<String, String>> kakaoRequest = new HttpEntity<>(params, headersAccess);
ResponseEntity<String> response = restTemplate.exchange("https://kauth.kakao.com/oauth/token"
, HttpMethod.POST, kakaoRequest, String.class);
NaverLoginVO naverVO = mapper.readValue(response.getBody(), NaverLoginVO.class);
RestTemplate은 Http통신을 하기위한 클래스이다.
HttpURLConnection을 이용한 API 데이터 받아오기 — 간편 웹프로그래밍 (tistory.com)
RestTemplate 말고 HttpURLConnection을 이용해서 post요청을 날릴 수도 있겠지만, 이번엔 RestTemplate를 써봤다.
RestTemplate의 사용법은 따로 설명하진 않겠다. HttpURLConnection과 구조적가 크게 다르지 않다.
먼저 MultiValueMap에 발급받은 code를 포함한 파라미터를 담아준다.
ResponseEntity를 이용해 restTemplate.exchange로 날린 요청의 응답값을 받아준 후,
해당 값을 ObjectMapper를 이용해 미리 작성해놓은 응답값 VO에 받아준다.
성공적으로 받았다면 , VO에 Access Token이 담겼다.
3. 사용자 정보 받아오기
2번의 과정과 그저 똑같다..
Access Token을 매개변수로 넣어주고, 사용자 정보를 받아오면 된다.
체크한 사용자정보에 따라 값을 가져올텐데, 일단 응답값 id는 필수적으로 가져온다.
카카오톡 회원 고유 id값을 이용해 회원가입과 로그인을 진행해주면 되겠다.
예를 들어 id값이 DB의 회원테이블에 없다면 그 값을 이용해서 회원가입을 시켜주고,
있다면 id값을 이용해 DB값을 세션에 부여해주면 되겠다.
이 과정을 한눈에보면 그저 저 표에 나와있는 것과 다를 바 없다 ( 당연... )
요즘 API를 만든다는게 어떤 의미인지 감을 잡아가는 것 같다.
협업의 경험이 매우 적지만, 백은 API를 만들고, 프론트는 값을 받아서 처리한다는게
어떤 의미인지 이해가 된다.
직접 api를 사용해보니 어떻게 만들어야 할지도 대충 그려지는 것 같고....
내가 만드는 서버 자체도 따져보자면 API지만,
남들이 사용 할 수 있는 공유할 수 있는 OpenAPI와 같은 모듈을 한번 만들어보고 싶다.
'SPRING BOOT > WhiteRecord' 카테고리의 다른 글
HttpURLConnection을 이용한 API 데이터 받아오기 (0) | 2022.02.07 |
---|---|
[스프링부트] 에디터 이미지업로드 시 임시폴더로 분리하기 (0) | 2022.02.05 |
스프링부트 Scheduler (4) | 2022.01.28 |
CK에디터로 올린 이미지에서 썸네일 뽑아내기 ( 정규식 ) (1) | 2022.01.28 |
지도 API 좌표값 소숫점 자르기 ( double형 소수값 자릿수 자르기 ) (3) | 2022.01.28 |