티스토리 뷰
서비스 기획 중 하나가 카카오톡을 기반으로 서비스 예정이라, 이에 관한 마케팅을 진행한다고 한다.
그런데 현재 서비스가 카카오 로그인을 지원하지 않고 있었다.
(사용자의 유입을 늘려야하는데!)
바로 구현에 들어가기로 했고, 카카오 Rest API 문서를 보면 Oauth 2.0 기반으로 회원가입/로그인을 지원한다고 한다.
그리고 아래와 같은 스퀀스 다이어그램을 하나 제공하는데...
이게 좀 문제가 있는게 SSR(서버 사이드 랜더링)을 위한 구조도이다.
그래서 CSR에서는 적합하지가 않다.
왜냐면 로그인 요청을 받은 서버에서 해당 사용자의 회원가입 여부를 확인해야하기 때문이다.
그리고 callback 페이지의 redirection도 해야하는데 서버에서는 적절하게 이를 제어할 수 없다.
때문에 FE 서버에서 해줘야할 역할이 생긴다.
(카카오 서버로 인가코드 받고 서버로 전달하기, 페이지 리다이렉션 등)
난 BE 작업만 했기 때문에 이번 포스팅에서는 BE에서 해야할 일만 알아보도록 하겠다.
FE가 해야할 일은 간단한 시퀀스 다이어그램? 정도로만 정리하고 넘어가려고 한다.
가장 먼저 해야할 일은 kakao developers에서 앱 등록을 하고 키를 받아야 한다.
차근차근 알아보자.
1. kakao developers에 앱 등록하기
kakao developers에 로그인 > 우측 상단 내 애플리케이션 클릭 > 애플리케이션 추가하기
앱을 생성하면 API를 사용하는데 쓰는 키를 확인 할 수 있다.
그리고 카카오 로그인 시 추가적으로 제공하는 정보에 동의하도록 하는 부분이다.
우리 서비스에서는 성별과 연령대도 함께 얻어오기 위해서 선택 동의로 넣었다. 이메일은 필수 항목으로 추가했다.
아래는 예시를 들고온 건데, 아래와 같이 선택 사항으로 사용자 추가 정보 이용에 동의하도록 한다.
이러면 토큰을 통해 사용자 정보를 가져올 때, 선택 사항에 동의한 항목들도 함께 받을 수 있다.
그리고 카카오에서는 추가적인 보안 사항으로 Client Secret 설정을 권장하는데, 카카오 로그인 > 보안에서 설정한다.
여기까지 developers kakao 페이지에서 설정할 내용은 끝났다.
한가지 더 있긴 한데, 이건 작성하면서 남겨보겠다.
2. 구현
구조를 한번에 보고가면 아래와 같다.
1. 인가코드는 FE 서버에서 받아오도록 처리해야한다. 2번에서 이어서 설명
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-code
https://kauth.kakao.com/oauth/authorize?client_id=[앱 REST API키]&redirect_uri=[인가코드를 전달받을 URI]&response_type=code
2. 위와 같이 요청하면, 카카오 페이지가 나오고 정상 로그인이 되었을 때, redirect_uri로 페이지가 이동하면서 redirect_uri의 쿼리스트링으로 인가코드(code)가 날아온다.
3. 여기서부터 BE가 관여한다. 인가 코드를 받아 사용자의 정보를 받아와 회원가입 여부를 판단하는 API를 하나 만들어줘야한다.
@GetMapping("/kakao/authenticate")
public ResultVo<UserKakaoInfoResponseDto> kakaoAuthenticate(@NotNull String code) {
return userAuthenticateService.kakaoAuthenticate(code);
}
4,5. 인가코드로 user 정보를 얻기 위한 access token 발급 요청
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-token
@FeignClient(name = "kakaoClient", url = "https://kauth.kakao.com/")
public interface KakaoOAuth2Client {
@PostMapping(value = "/oauth/token", consumes = "application/x-www-form-urlencoded")
KakaoTokenResponseDto generateToken(
@RequestParam("grant_type") String grantType,
@RequestParam("client_id") String clientId,
@RequestParam("redirect_uri") String redirectUri,
@RequestParam("client_secret") String clientSecret,
@RequestParam("code") String code
);
}
사용자 정보를 받기위해선 인가코드로 토큰을 먼저 생성해야 한다.
content type은 카카오에서 application/x-www-form-urlencoded 받기 때문에 별도의 처리가 필요하다.
응답 규격은 위 링크를 확인한다.
try {
KakaoTokenResponseDto token = kakaoOAuth2Client.generateToken("authorization_code", clientId, redirectUri, clientSecret, code);
} catch (Exception e) {
throw new BadRequestException("카카오 인증 실패");
}
인가코드에서 사용됐던 파라미터들이 거의 그대로 쓰인다.
grantType : authorization_code으로 고정
clientId : 앱 REST API 키
client secret : 위에서 보안을 위해 추가 발급받은 키
code : 인가코드
응답 규격은 위의 링크에서 확인할 수 있다.
6. 카카오 서버로 사용자 정보 요청
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#req-user-info
@FeignClient(name = "kakaoApiClient", url = "https://kapi.kakao.com/")
public interface KakaoApiClient {
@PostMapping(value = "/v2/user/me", consumes = "application/x-www-form-urlencoded")
KakaoUserInfoDto getUserInfo(@RequestHeader("Authorization") String authorization);
}
받아올 수 있는 정보가 진짜 많다. 받아올 수 있는 정보는 여기에서 확인 가능.
@Data
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public class KakaoUserInfoDto {
private long id;
private String connectedAt;
private KakaoAccount kakaoAccount;
@Data
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public static class KakaoAccount {
private boolean hasEmail;
private boolean emailNeedsAgreement;
private boolean isEmailValid;
private boolean isEmailVerified;
private String email;
private boolean hasAgeRange;
private boolean ageRangeNeedsAgreement;
private String ageRange;
private boolean hasGender;
private boolean genderNeedsAgreement;
private String gender;
}
}
내가 필요한 정보는 이메일, 연령대, 성별 정도이므로 필요한 정보만 가져올 수 있도록 처리했다.
7,8,9는 서버의 서비스로직으로 처리해야할 일이다.
여기서 유니크한 값은 id다.
id 기준으로 이메일을 포함해 카카오 사용자들을 기록해서,
이미 회원가입한 이력이 있으면 로그인 페이지로 이동
회원가입한 이력이 없으면 회원가입 페이지로 이동시키면 된다.
주의할점
"msg": "ip mismatched! callerIp=XXX.XXX.XXX.XXX. check out registered ips.",
"code": -401
작업하다보면 ip가 허용되지 않았다는 에러가 나는데, 이는 developers kakao에 가서 고급설정 > 허용 IP 주소에서 허용 IP를 등록하면된다.
마치며
글을 쓰다보니 REST API 에서 그려준 시퀀스 다이어그램 보다 여기가 현재 상황에 더 적합한 그림인 것 같다.
다이어그램이라기보다는 그냥 서비스 흐름도 같지만, 훨씬 상황에 맞고 직관적이다.
이번 작업을 하면서 FE에서의 작업을 조금 더 이해할 필요가 있다는 생각이 들었다.
아직 FE에서 서버를 어떨 때 사용해야 할지 명확히 모른다는 게 느껴졌기 때문이다.
'개발 > SPRING' 카테고리의 다른 글
스프링부트에서 JWT 적용하기 - 4. 스프링 시큐리티에 적용 - CustomAuthority 생성하기 (1) | 2023.12.31 |
---|---|
[Spring/Java] Rollback과 Exception, 그리고 @Transactional (1) | 2023.12.30 |
스프링부트에서 SMS 본인 인증 구현하기 - 2. 어뷰징 막기 (0) | 2023.10.30 |
스프링부트에서 SMS 본인 인증 구현하기 - 1. Twilio로 구현 (1) | 2023.10.24 |
스프링부트에서 JWT 적용하기 - 3. 필터(filter)에 적용 (0) | 2023.10.10 |
- Total
- Today
- Yesterday
- Elastic cloud
- lambda
- S3
- elasticsearch
- ChatGPT
- 람다
- AWS EC2
- OpenAI
- 티스토리챌린지
- GIT
- serverless
- MySQL
- AOP
- Kotlin
- OpenFeign
- openAI API
- java
- cache
- CloudFront
- springboot
- Log
- Spring
- terraform
- AWS
- 스프링부트
- 후쿠오카
- 오블완
- EKS
- docker
- JWT
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |