티스토리 뷰
스프링/스프링부트 RestAPI 프로젝트
spring boot REST API Web 프로젝트 (12 - 2) - OAuth 2.0 카카오 로그인 part.1 Authorization code + Token 발급
구름뭉치 2021. 8. 29. 13:27스프링 부트 REST API WEB 프로젝트
깃헙 링크
https://github.com/choiwoonsik/springboot_RestApi_App_Project/tree/main/restApiSpringBootApp
수행 목록
- 환경구성 및 helloworld 출력
- H2 DB 연동
- Swagger API 문서 연동
- REST API 설계
- RestControllerAdvice를 이용한 통합 예외 처리
- Entity - DTO 분리
- MessageSource를 이용해 예외 메시지 다국화
- JPA Aduting을 이용해 객체 생성시간/수정시간 적용
- 스프링 시큐리티 + Jwt를 이용해서 인증 및 권한 체크
- 스프링 시큐리티 AuthenticationEntryPoint, AccessDenied로 인증 및 인가 예외처리
- Jwt AccessToken + RefreshToken으로 보안성과 사용자 편의성 고도화하기
- JUnit Test (단위 테스트)
- JUnit Test (통합 테스트)
- OAuth 2.0 정리
- OAuth 2.0 카카오 로그인 part.1 Authorization code + Token 발급
- OAuth 2.0 카카오 로그인 part.2 토큰으로 회원 가입 / 로그인
- OAuth 2.0 카카오 로그인 테스트 검증
- 환경별 설정을 위해서profile 분리하기
앞에서 정리한 OAuth 2.0을 바탕으로 직접 구현해본다
- 정리글 : OAuth 2.0 정리
카카오 OAuth 로직
위와 같은 로직으로 카카오 로그인이 돌아간다.
카카오 로그인 사용을 위한 작업
- 카카오 Developers 사이트에 가서 자신의 APP을 생성
- 로그인 페이지 / 콜백 페이지 연동
- AccessToken을 통해 가입 및 로그인
1. 카카오 Developers 설정
웹 앱의 주소 등록 : 앱설정 -> 플랫폼
콜백 주소 (Redirect URI) 등록 : 카카오 로그인
2. 로그인 페이지 / 콜백 페이지 구현
카카오와 통신이 필요하므로 RestTemplate를 빈으로 등록
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
카카오 연동 결과 Json을 객체로 매핑하기 위해 Gson 라이브러리를 사용. 의존성 추가
// Json을 결과로 매핑하기 위한 의존성
implementation 'com.google.code.gson:gson'
2- 1. 카카오 api와 연동하기 위한 설정정보 application.yml 작성
- https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
- 카카오 API 내용은 공식 사이트에 잘 정리되어있으니 참고해서 작성하면 된다.
인가코드받기
GET /oauth/authorize?client_id={REST_API_KEY}&redirect_uri={REDIRECT_URI}&response_type=code HTTP/1.1
Host: kauth.kakao.com
https://kauth.kakao.com/oauth/authorize?response_type=code&client_id={REST_API_KEY}&redirect_uri={REDIRECT_URI}
토큰받기
POST /oauth/token HTTP/1.1
Host: kauth.kakao.com
Content-type: application/x-www-form-urlencoded;charset=utf-8
사용자정보 가져오기
GET/POST /v2/user/me HTTP/1.1
Host: kapi.kakao.com
Authorization: Bearer {ACCESS_TOKEN}
Content-type: application/x-www-form-urlencoded;charset=utf-8
사용자 연결 끊기 (재동의를 위해 구현)
POST /v1/user/unlink HTTP/1.1
Host: kapi.kakao.com
Authorization: Bearer {ACCESS_TOKEN}
위 내용을 가지고 application.yml을 작성
social:
kakao:
client-id: {REST_API_PRIVATE_KEY}
redirect: /oauth/kakao/redirect
url:
login: https://kauth.kakao.com/oauth/authorize
token: https://kauth.kakao.com/oauth/token
profile: https://kapi.kakao.com/v2/user/me
unlink: https://kapi.kakao.com/v1/user/unlink
url:
base: http://localhost:8080
- [http://localhost:8080/oauth/kakao/login]로 접속
- 카카오 로그인 버튼이 있는 창을 띄어줌, 해당 버튼을 누르면 요청 URL을 보내고 카카오 로그인 창이 뜨게 된다.
- 요청 URL은 [인가 코드 받기]에 있는 URL이다.
- 요청 URL 형식 : https://kauth.kakao.com/oauth/authorize?response_type=code&client_id={REST_API_KEY}&redirect_uri={REDIRECT_URI}
2- 2. 카카오 인가 코드 받기
카카오 서버에 나의 {REST_API_KEY} 와 {REDIRECT_URI}를 담아서 GET 요청
@Value("${url.base}")
private String baseUrl;
@Value("${social.kakao.client-id}")
private String kakaoClientId;
@Value("${social.kakao.redirect}")
private String kakaoRedirectUri;
@GetMapping("/login")
public ModelAndView socialLogin(ModelAndView mav) {
StringBuilder loginUri = new StringBuilder()
.append(env.getProperty("social.kakao.url.login"))
.append("?response_type=code")
.append("&client_id=").append(kakaoClientId)
.append("&redirect_uri=").append(baseUrl).append(kakaoRedirectUri);
mav.addObject("loginUrl", loginUri);
mav.setViewName("social/login");
return mav;
}
카카오톡 로그인 버튼을 갖는 view 만듬 : resources/templates/social/login.ftl
<button onclick="popupKakaoLogin()">KakaoLogin</button>
<script>
function popupKakaoLogin() {
window.open('${loginUrl}', 'popupKakaoLogin', 'width=700,height=500,scrollbars=0,toolbar=0,menubar=no')
}
</script>
- 사용자가 카카오 로그인 버튼을 누르면
- -> 위에서 작성한 loginUri로 요청이 가고 카카오톡 로그인 창이 뜸
- -> 사용자는 로그인 후 동의항목을 체크하고 진행
- -> 이때 URL은 client_id와 redirect_uri를 가지고 있고, 카톡 서버가 검증 후 redirect_uri로 사용자의 Authorization_code (인가 코드)를 쿼리 파라미터로 포함해서 리다이렉트 한다. (이때 카카오는 카카오의 회원정보를 나의 앱과 연동시킨다.)
카카오가 돌려준 AuthorizationCode를 가지고 토큰 받기
redirect_uri는 내가 미리 카톡 API 서버에 지정해둔 것이므로 해당 리다이렉트 주소에 맞게 처리하면 된다.
@GetMapping(value = "/redirect")
public ModelAndView redirectKakao(
ModelAndView mav,
@ApiParam(value = "Authorization Code", required = true)
@RequestParam String code) {
mav.addObject("authInfo", kakaoService.getKakaoTokenInfo(code));
mav.setViewName("social/redirectKakao");
return mav;
}
쿼리 파라미터에서 [인가 코드]를 얻어서 카카오에게 토큰을 요청한다.
- kakaoService.getKakaoTokenInfo(code) 메소드를 작성하자
2-3. 카카오 토큰
- [grant_type, 인가 코드, client_id, redirect_uri] 를 포함해서 카카오에 POST 요청해주면 카카오가 토큰을 돌려준다.
- 해당 토큰을 매핑하기 위한 RetKakaoOAuth객체를 만든다.
RetKakaoOAuth 객체
package com.restApi.restApiSpringBootApp.dto.social;
@Getter
public class RetKakaoOAuth {
private String token_type;
private String access_token;
private Integer expires_in;
private String refresh_token;
private String refresh_token_expires_in;
private String scope;
}
❗️이때 gson을 이용하기위해 객체의 프로퍼티는 json의 key-value의 key이름과 동일하게 작성한다❗️
2.4 전달받은 [인가코드]로 [Token] 발급받기
- [grant_type, 인가 코드, client_id, redirect_uri]를 담아서 POST 요청을 보낸다.
- 정상적인 경우 Token을 전달받을 수 있다. 토큰 값을 RetKakaoOAuth객체로 매핑한다.
카카오 토큰 데이터를 RestKakaoToken으로 매핑
public RetKakaoOAuth getKakaoTokenInfo(String code) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_id", kakaoClientId);
params.add("redirect_uri", baseUrl + kakaoRedirectUri);
params.add("code", code);
String requestUri = env.getProperty("social.kakao.url.token");
if (requestUri == null) throw new CCommunicationException();
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
ResponseEntity<String> response = restTemplate.postForEntity(requestUri, request, String.class);
if (response.getStatusCode() == HttpStatus.OK)
return gson.fromJson(response.getBody(), RetKakaoOAuth.class);
throw new CCommunicationException();
}
응답이 제대로 왔다면
- gson을 이용해서 전달받은 Json 데이터를 ReKakaoOAuth로 매핑한다.
- 이때 gson을 이용하려면 객체의 프로퍼티는 json의 key-value의 key이름과 동일해야한다.
발급받은 토큰 확인을 위한 view : resources/templates/social/redirectKakao.ftl
<ol>
<li>token_type : ${authInfo.token_type}</li>
<li>access_token : ${authInfo.access_token}</li>
<li>expires_in : ${authInfo.expires_in}</li>
<li>refresh_token : ${authInfo.refresh_token}</li>
<li>refresh_token_expires_in : ${authInfo.refresh_token_expires_in}</li>
<li>scope : ${authInfo.scope}</li>
</ol>
결과적으로 유저는 카카오 로그인을 통해 카카오로부터 Token을 발급 받았다. 이제 이 토큰을 이용해서 카카오에게 유저 정보를 요청하고 해당 유저 정보가 유효하다면, 그 정보를 이용해서 회원가입 시키면 된다.
-
내용이 길어져서 끊고 바로 다음 장에서 이어서 진행
반응형
'스프링 > 스프링부트 RestAPI 프로젝트' 카테고리의 다른 글
Comments
반응형
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday