소셜 로그인
사람들이 자주 사용하는 웹이나 모바일 앱을 보면 거의 대부분은 소셜 로그인이 가능하다.
사용자 입장에서 보면 소셜 로그인은 굉장히 간편하고 여러 사이트를 관리하기 쉬워진다.
개발자 입장에서도 간편한 것은 마찬가지다. 따로 어떠한 사용자의 정보를 받을 필요 없이 서비스를 이용하는 사람이 소셜 로그인을 하는지 확인하고 적절한 요청과 응답을 보내주면 되기 때문에 보다 간편하게 회원의 인증과 인가 작업을 할 수 있다.
처음에 소셜 로그인을 어떻게 구현해야 되는지 잘 몰랐는데 강의를 듣고 찾아보니 각 소셜 기업마다 API를 공개하여 편리하게 사용할 수 있도록 만들어 놓았다는 것을 알게 되었다.
이제 내가 만든 서비스에서 소셜 로그인을 구현하려면 원하는 소셜 기업에 들어가 API 문서를 찾아보고 설명서대로 코드를 구현하면 잘 작동하게 된다.
kakao 로그인
여러 기업들이 소셜 로그인을 API로 제공하고 있지만 그중 우리나라 기업 중에서 사람들이 가장 많이 사용하는 카카오 로그인을 구현해 봤다.
카카오 개발자 사이트에 들어가서 간단히 내 애플리케이션을 만들고 개발을 시작했다.
먼저 클라이언트에서 카카오 로그인을 요청해야 되는데 "도구 --> JS SDK 데모 --> 카카오 로그인 --> 로그인" 으로 이동하게 되면 간단한 카카오 로그인 버튼을 클릭할 수 있는 자바스크립트 코드를 제공해 준다.
제공된 자바스크립트 데모를 통해서 카카오 로그인 버튼을 클릭하게 되면 3가지 과정을 거쳐서 로그인이 이뤄지게 된다.
3가지 과정을 하나씩 살펴보자.
1. 인가 코드 받기
클라이언트가 프론트에게 로그인 페이지를 요청하게 되면 해당 프론트 서버에서는 카카오 로그인 페이지를 반환하게 된다.
프론트에서 반환해 주는 카카오 로그인 버튼에는 카카오에게 인가코드를 요청하는 코드가 포함되어 있어서 해당 로그인 버튼을 클릭하게 되면 카카오 서버로 인가코드 요청을 보내게 된다.
카카오에서는 해당 사용자가 로그인을 안 했다면 로그인 페이지를 전달해 주고 로그인을 했으면 서비스 동의 페이지를 보여준다.
동의 항목을 선택하고 계속하기 버튼을 클릭하게 되면 카카오에게 인가 코드를 요청하게 된다.
카카오에게 정상적으로 인가 코드 요청이 가게 된다면 미리 등록해 둔 Redirect URI로 인가 코드를 전송해 주게 되고 개발자가 만들어둔 컨트롤러로 요청이 들어오게 된다.
2. 토큰 받기
이제 카카오로부터 받은 인가 코드를 통해서 카카오에게 토큰 발급을 요청해야 한다.
토큰을 받는 과정까지 마쳐야 카카오 로그인을 정상적으로 수행할 수 있기 때문에 필수로 구현해야 되는 과정이다.
카카오에서 제공하는 API 문서를 보면 어떻게 요청해서 토큰을 받을 수 있는지 확인할 수 있다.
메서드 | URL |
POST | https://kauth.kakao.com/oauth/token |
위의 URL로 POST 요청을 보내게 되면 토큰 발급을 해주는데 이때 필수 파라미터를 포함해서 요청을 해야 된다.
public String getAccessToken(String code) {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.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", clientId);
params.add("redirect_uri", "http://localhost:8080/member/kakao");
params.add("code", code);
HttpEntity<MultiValueMap<String, String>> requestBody = new HttpEntity<>(params, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Object> response = restTemplate.exchange(
"https://kauth.kakao.com/oauth/token",
HttpMethod.POST,
requestBody,
Object.class
);
String result = "" + response;
String accessToken = result.split(",")[1].split("=")[1];
return getUserInfo(accessToken);
}
코드를 살펴보면 HTTP 요청 메시지를 만들어서 API 문서에 있는 URL로 요청을 보내게 되는데 HTTP 헤더와 본문(Body) 부분에서 카카오가 지정한 필수 부분을 꼭 포함해서 요청을 보내줘야 한다.
요청에 대한 반환 값으로 ResponseEntity 클래스의 response로 받게 되면 해당 변수에서 accessToken 값을 추출할 수 있고 그것을 가지고 3번 과정인 추가 기능을 구현할 수 있게 된다.
그림으로 살펴보면 restTemplate의 exchange 메서드를 사용하여 Rest API를 호출하게 되고 그 반환 값으로 카카오에서 받은 응답 결과를 받을 수 있게 된다.
3. 추가 기능
카카오로부터 access 토큰을 발급받으면서 로그인 과정이 끝났다.
이제는 해당 access 토큰을 가지고 여러 가지 추가 기능을 사용할 수 있다.
여러 가지 기능들 중에서 사용자 정보를 가져오는 기능을 구현해야 되는데 그 이유는 아직 백엔드 서버에서는 카카오 로그인을 한 사용자의 정보를 모르기 때문이다.
카카오는 해당 사용자의 이름이나 닉네임, 이메일 등의 정보를 알고 있지만 현재 백엔드 서버에서는 그러한 정보를 모르고 있기 때문에 카카오로부터 사용자 정보를 가져와야 된다.
참고로 처음에 인가 코드를 요청할 때 진행했던 동의 항목에서 체크된 것들만 가져올 수 있다.
이전과 똑같이 카카오에서 제공하는 API 문서를 통해서 어떻게 요청을 해야 되는지 확인한다.
메서드 | URL |
GET/POST | https://kapi.kakao.com/v2/user/me |
사용자 정보를 받아오는 기능은 카카오 로그인에서 제공하는 추가 기능이기 때문에 access 토큰이 있어야 한다.
private String getUserInfo(String accessToken) {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
headers.add(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=utf-8");
HttpEntity request = new HttpEntity<>(headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Object> response = restTemplate.exchange(
"https://kapi.kakao.com/v2/user/me",
HttpMethod.GET,
request,
Object.class
);
System.out.println(response);
String nickname = "" + response;
String username = nickname.split(",")[3].split("nickname=")[1].split("}")[0];
System.out.println("username = " + username);
return username;
}
코드를 먼저 살펴보면 이전에 토큰을 발급받았던 것을 매개변수로 받아오고 해당 토큰을 HTTP header에 담아준다.
API 문서를 보면 access 토큰 앞에 Bearer가 있어야 정상적으로 요청을 보낼 수 있기 때문에 문자열 연산을 이용하여 만들어 준다.
그 다음으로 카카오에서 요구하는 필수 데이터를 헤더에 추가해 주고 명시해 놓은 메서드를 사용하여 URL로 요청을 보내준다.
마찬가지로 restTemplate을 사용해서 Rest API를 호출하게 되고 반환 값을 받아서 내가 필요한 데이터만 추출해서 사용한다.
그림으로 살펴보면 헤더에 필요한 정보들을 담고 요청을 보내게 되면 카카오는 access 토큰 값을 검증하고 해당 토큰의 사용자 정보를 전송해 주게 된다.
받은 사용자 정보에서 카카오 로그인을 한 사용자의 이름을 추출하여 DB에서 확인하고 없으면 저장하게 된다.
@RequestMapping(method = RequestMethod.GET, value = "/kakao")
public ResponseEntity<Object> socialLogin(String code) {
String userName = socialLoginService.getAccessToken(code);
Member user = memberService.getMemberByUserName(userName);
if (user == null) {
socialLoginService.socialSignUp(userName);
}
return ResponseEntity.ok().body(socialLoginService.socialLogin(userName));
}
코드를 살펴보면 getAccessToken 메서드를 통해서 사용자 이름을 반환받고, 해당 이름을 getMemberByUserName 메서드를 통해서 DB를 통해 찾게 된다.
만약 DB에 없는 사용자면 socialSignUp 메서드를 통해 DB에 저장하게 되고 DB에 존재하는 사용자라면 jwt 토큰을 발급해서 전달해 주게 된다.
그림과 같은 과정이 끝나면 클라이언트에게 jwt 토큰과 프론트 서버의 리다이렉트 주소를 전송하게 되고 해당 클라이언트는 발급 받은 jwt 토큰을 가지고 프론트 서버의 리다이렉트 주소로 가게 된다.
마지막으로 프론트 서버에서는 클라이언트에서 전달받은 jwt 토큰을 쿠키나 로컬 스토리지에 저장하고 메인 페이지로 리다이렉트를 해준다.
'스프링' 카테고리의 다른 글
스프링 - 스프링 부트 프로젝트 배포하기 (0) | 2024.01.10 |
---|---|
스프링 - JWT (0) | 2023.12.28 |
스프링 - 스프링 시큐리티 (0) | 2023.12.25 |
스프링 - 레이어드 아키텍처 (0) | 2023.12.21 |
스프링 - 스프링 프레임워크의 기초 (0) | 2023.12.20 |