0. 소셜로그인 ?
1. 카카오 소셜로그인
1. 카카오 로그인 과정
- 사용자가 서비스에서 카카오 로그인 버튼을 클릭하면 서비스는 카카오 인증 서버로 인가 코드 발급을 요청
- 카카오 인증 서버는 사용자에게 인증을 요청 (= 계정 정보를 입력해 로그인하는 화면 출력)
- 카카오 인증 서버는 사용자 인증 성공 시, 서비스 앱의 동의 항목 설정을 바탕으로 사용자에게 동의 화면을 출력
- 사용자가 필수 동의 항목에 동의하고 로그인을 요청하면, 카카오 인증 서버는 인가 코드(Authorization Code)를 발급해 서비스 앱에 등록된 Redirect URI로 전달
- 서비스는 전달받은 인가 코드로 토큰을 요청하여 받음
2. 회원 확인 및 가입
- 서비스는 카카오 로그인을 완료하여 발급받은 토큰으로 사용자 정보 가져오기를 요청
- 카카오 API 서버는 요청 시 사용된 토큰의 유효성을 검증하고, 요청을 처리하고 서비스에 응답
- 서비스 서버는 카카오로부터 제공받은 사용자 정보로 해당 사용자가 서비스에 회원 가입되어 있는지 확인
- 이미 회원 가입된 사용자: Step 3의 서비스 로그인 단계 수행
- 아직 회원 가입되지 않은 사용자: 카카오에서 제공받은 사용자 정보로 서비스 데이터베이스에 회원 가입 처리
2. 사전준비
카카오 소셜로그인을 하기 위해서는 사전 설정이 필요하다.
2-1. 애플리케이션 추가하기
앱 이름과 사업자명을 입력하고 저장을 누른다.
2-1. 플랫폼 등록하기
2-2. 카카오 로그인 활성화
[활성화 설정]의 [상태]가 [OFF]인 경우, 카카오 로그인 요청 시 KOE004 에러가 발생한다.
그러므로 활성화 설정 상태를 ON로 설정하여 실제 서비에서 카카오 로그인 화면이 연결되도록 하자.
2-3. 리다이렉트 URI 등록
주의 사항
- Redirect URI는 최대 10개까지 등록할 수 있습니다.
- Redirect URI는 HTTP 및 HTTPS 프로토콜, 80, 443 포트를 허용합니다.
- Redirect URI는 HTTP, HTTPS 프로토콜을 구분하므로 각각 등록해야 합니다.
나의 경우 http://localhost:8080/app/users/kakao 으로 지정해주었다. (임의로 지정해주면 된다.)
2-4. 동의항목
[내 애플리케이션] > [카카오 로그인] > [동의 항목] > [개인정보]에서 설정가능하다.
아래 사진과 같은 정보들을 가져올 수 있으며, 나의 경우에는 이메일만 받아오도록 설정해주었다.
3. 자세히 알아보자
사전 준비가 끝났다면 소셜로그인에 대한 과정을 자세히 알아보자.
3-1. 인가코드 발급
사용자가 카카오 로그인을 요청하게 되면, 카카오 서버는 Redirect URI로 인가코드(authorization code)를 발급하게 된다.
GET /oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code
애플리케이션을 등록하였다면 앱설정 > 요약정보 에서 자신의 앱키를 볼 수 있는데, 이때 Rest Api 키를 client_id에 넣어주면 된다.
또한 redirect_uri의 경우 앞서 설정한 리다이렉트 주소를 넣어주면 된다!
이 과정을 거쳤다면 다음과 같이 설정한 uri로 리다이렉트된 것을 볼 수 있고, code = ~~~로 인가코드가 발행된 것을 볼 수 있다.
3-2. 액세스 토큰 발급
앞서 발급한 인가코드로 카카오 서버에 액세스토큰을 요청할 수 있다.
필수 파라미터를 포함해 POST로 /ouath/token으로 요청해야 하며, 요청 성공 시 응답은 토큰과 토큰 정보를 포함하게 된다.
Rest APi 키와 리다이렉트 주소의 경우에는 외부로 노출시키지 않아야 하므로 application.yml에 지정하여주었다.
@RequiredArgsConstructor
@Service
public class OAuthService {
private final UserRepository userRepository;
@Value("${spring.security.oauth2.client.registration.kakao.client-id}")
private String kakao_client_id;
@Value("${spring.security.oauth2.client.registration.kakao.redirect-uri}")
private String kakao_redirect_uri;
/* 액세스 토큰 발급 */
public String getKakaoAccessToken (String code) {
String accessToken = "";
String refreshToken = "";
String reqURL = "https://kauth.kakao.com/oauth/token";
try {
URL url = new URL(reqURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
StringBuilder sb = new StringBuilder();
sb.append("grant_type=authorization_code");
sb.append("&client_id="+kakao_client_id);
sb.append("&redirect_uri="+kakao_redirect_uri);
sb.append("&code=" + code);
bw.write(sb.toString());
bw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
String result = "";
while ((line = br.readLine()) != null) {
result += line;
}
JsonElement element = JsonParser.parseString(result);
accessToken = element.getAsJsonObject().get("access_token").getAsString();
refreshToken = element.getAsJsonObject().get("refresh_token").getAsString();
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
return accessToken;
}
}
3-3. 사용자 정보 요청
액세스토큰까지 발급받았다면, 이 액세스토큰을 통해 카카오 서버에 사용자의 정보를 요청할 수 있다.
- 요청 URL : https://kapi.kakao.com/v2/user/me
- 요청 메서드 : POST
- 헤더 : Authorization Bearer 액세스토큰
@RequiredArgsConstructor
@Service
public class OAuthService {
/* ... */
public KakaoResponse getKakaoUserInfo(String accessToken) {
HashMap<String, Object> userInfo = new HashMap<>();
String reqURL = "https://kapi.kakao.com/v2/user/me";
try {
URL url = new URL(reqURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
String result = "";
while ((line = br.readLine()) != null) {
result += line;
}
JsonElement element = JsonParser.parseString(result);
JsonObject kakaoAccount = element.getAsJsonObject().get("kakao_account").getAsJsonObject();
String email = kakaoAccount.getAsJsonObject().get("email").getAsString();
String id = element.getAsJsonObject().get("id").getAsString();
userInfo.put("email", email);
userInfo.put("id", id);
} catch (IOException e) {
e.printStackTrace();
}
return new KakaoResponse((String)userInfo.get("id"), (String)userInfo.get("email"));
}
@Getter
@AllArgsConstructor
public class KakaoResponse {
private String socialIdx;
private String email;
}
4. 테스트 해보기
컨트롤러의 전반적인 흐름은 다음과 같다
- OAuthService의 getKakaoAccessToken()메서드에 요청 파라미터로 받은 인가코드를 전달하여 액세스 토큰은 발급 받는다.
- OAuthService의 getKakaoUserInfo() 메서드에 액세스토큰을 파라미터로 전달하여 유저의 소셜 식별자와 이메일을 Json형태로 받는다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/oauth")
public class OAuthController {
@ResponseBody
@GetMapping("/kakao/info")
public ResponseEntity<KakaoResponse> getKakaoUserInfo(@RequestParam String code) {
String accessToken = OAuthService.getKakaoAccessToken(code);
KakaoResponse kakaoUserInfo = OAuthService.getKakaoUserInfo(accessToken);
return new ResponseEntity<>(kakaoUserInfo, HttpStatus.OK);
}
}
포스트맨 결과는 다음과 같다!
소셜로그인 id와 이메일이 잘 발급된 것을 볼 수 있다.
'Spring' 카테고리의 다른 글
Mockito 공식문서 읽고 정리하기 (1) (0) | 2023.04.07 |
---|---|
JDBC Template 공부하기1 (query, queryForObject, update) (0) | 2022.09.28 |
댓글