사이드 프로젝트에서 제가 로그인 기능을 개발하지 않아서인지 사이드 프로젝트의 인증과 인가 부분을 이해하기가 어려웠습니다.
Oauth를 이용한 최근 어플리케이션들에서는 필수로 알아야 하는 지식이므로 꼭 이해하고 넘어가고 싶었습니다.
(사실 옛날에 시도했다가 동작은 되지만 이해는 하나도 못 하는 수준으로 개발하였기에 제대로 이해하고 싶은 마음도 있습니다. 😁)
✅ 노랑색 마킹한 부분을 잘 확인해 주세요. ✅
1. Kakao Developers 설정하기
1-1. 내 애플리케이션 등록

- Kakao Developers에 접속하여 내 애플리케이션 추가하기 버튼을 눌러서 애플리케이션을 등록합니다.
1-2. 카카오 로그인 활성화하기

- 1-1에서 등록한 내 애플리케이션을 클릭하여 설정 화면으로 이동합니다.


- 사이드 메뉴에서 카카오 로그인을 클릭하고 카카오 로그인을 활성화해줍니다.
1-3. Redirect URI 등록하기

- Redirect URI 등록 버튼을 클릭하여 Redirect URI를 등록해 줍니다. 저는 따로 배포하지 않고 진행하였기에
http://localhost:8080/oauth/kakao를 Redirect URI로 등록하였습니다.
1-4. 동의항목 설정하기


- 동의항목에서 닉네임을 필수동의로 변경해 줍니다. (여기서 필수동의가 카카오의 Resource서버에서 제공해주는 유저 정보가 됩니다.)
- 원래 카카오 계정도 필수 동의를 받아야 하는데, Biz앱 전환을 하지 않으면 카카오에서 이메일을 제공해 주지 않습니다.
2. 인가 코드 받기

위 이미지는 카카오 로그인 과정을 나타내고 있는 시퀀스 다이어그램입니다. 지금부터 하는 게 Step 1에 해당하는 부분입니다.
2-1. GET https://kauth.kakao.com/oauth/authorize 요청 보내기
https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}

시퀀스 다이어그램상 가장 처음 해야 할 것은 GET https://kauth.kakao.com/oauth/authorize을 처리하는 것입니다. 카카오 로그인시 일반적으로 GET 요청은 흔히 보이는 카카오 로그인 버튼을 클릭했을 때 가장 처음 동작합니다.
즉 사용자가 버튼을 클릭하는 순간 일어나는 일은
- 인가 코드를 받는다.
- 받은 인가 코드로 Access Token을 받는다.
- Access Token으로 유저 정보를 받는다.
위 3개의 과정으로 진행되고 있는 것입니다.
다시 본론으로 돌아와서 저는 카카오 로그인 버튼이 따로 없기 때문에카카오 버튼만 있는 화면을 하나 만들어 주겠습니다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>카카오 로그인</title>
</head>
<body>
<a href="/login/kakao">
<img src="/img/kakao_login.png" alt="카카오 버튼" style="width: 150px; height: auto;">
</a>
</body>
</html>
버튼에 걸려있는 uri가 /login/kakao 이므로 이것을 처리해주는 컨트롤러를 하나 만들어줍니다.
@RequestMapping("/login")
@RequiredArgsConstructor
@Controller
public class LoginController {
@GetMapping("/{provider}")
public String login(@PathVariable String provider) {
String url = "https://kauth.kakao.com/oauth/authorize?" +
"client_id=" + "{REST API KEY}" +
"&redirect_uri=" + "http://localhost:8080/oauth/" + provider +
"&response_type=code";
return "redirect:" + url;
}
}
위 Controller 코드에서 보면 만들어주고 있는 url이 카카오에서 제공해주는 예제와 똑같은 형식임을 알 수 있습니다. 이렇게 하면 인가 코드를 받을 수 있습니다.

인가 코드는 정상적으로 수행되었을 경우 위와 같은 형태로 응답됩니다.
3. 토큰 받고, 유저 정보 받기

위에서 인가 코드를 받는 과정을 진행했는데 인가 코드를 잘 받은 것을 어떻게 알 수 있을까요? 시퀀스 다이어그램을 보면 Redirect URI로 인가 코드를 전달한다고 되어 있습니다. 여기서 말하는 Redirect Uri가 1-3. Redirect URI 등록하기에서 설정했던 그 Redirect Uri입니다.
저는 Redirect Uri를 localhost:8080/oauth/kakao로 설정하였기 때문에 이 uri로 Redirect 되었을 때의 경우를 처리해 주어야 합니다. 그리고 요청 url에는 위에서 받은 인가 코드가 같이 있을 겁니다.
@Slf4j
@RequestMapping("/oauth")
@RequiredArgsConstructor
@RestController
public class OauthController {
@GetMapping("/{provider}")
public JsonNode login(@RequestParam String code, @PathVariable String provider) {
log.info("provier: {}, code: {}", provider, code);
// 1. 헤더 생성
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("Accept", "application/json");
// 2. 바디 생성
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code"); // grant_type은 고정 값
params.add("client_id", "{REST API KEY}"); // rest api key
params.add("redirect_uri", "http://localhost:8080/oauth/kakao"); // redirect_uri
params.add("client_secret", "{SECRET_KEY}");
params.add("code", code);
// 3. 헤더랑 바디 합치기
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
// 4. HTTP 요청
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<JsonNode> response = restTemplate.exchange(
"https://kauth.kakao.com/oauth/token",
HttpMethod.POST,
request,
JsonNode.class
);
// 5. token 발급이 잘 되었나 확인
log.info("response: {}", response);
// 6. Resource 서버에 유저 정보를 요청
HttpHeaders requestResourceHeader = new HttpHeaders();
requestResourceHeader.set("Authorization", "Bearer " + response.getBody().get("access_token").asText());
requestResourceHeader.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<Object> requestEntity = new HttpEntity<>(requestResourceHeader);
JsonNode body = restTemplate.exchange(
"https://kapi.kakao.com/v2/user/me",
HttpMethod.POST,
requestEntity,
JsonNode.class
).getBody();
return body;
}
}
위 코드에서는 1부터 5까지의 과정이 토큰을 발급받는 과정입니다. 그리고 6번은 유저 정보를 요청하는 과정입니다. 다음으로 해야 할 일은 유저 정보를 받은 이후에 유저 정보를 데이터베이스에 저장하는 일입니다.
'공부 > Spring' 카테고리의 다른 글
| [JUnit] 여러 매개변수를 테스트해야 한다면? @ParameterizedTest (0) | 2024.08.25 |
|---|---|
| [Spring]Spring Converter를 사용한 이유: Enum 타입을 소문자로 받기 위하여 (0) | 2024.08.05 |