Kakao OAuth를 통한 로그인
시퀀스
준비
카카오 개발자 센터(https://developers.kakao.com/)로 가서 내 애플리케이션에 카카오 로그인 기능을 활성화 하고 REST API 키 가져 오기
1
2
3
4
5
6
7
8
9
| 카카오 로그인 기능 활성화 방법
1) 내 애플리케이션 > 제품 설정 > 카카오 로그인
: 활성화 설정 => ON
Redirect URI => http://back_ip:8080/kakaoLoginCallback
동의 항목 => account_email (개인 개발자 비즈 앱 전환이 되어야 동의항목으로 설정할 수 있음)
2) 내 애플리케이션 > 앱 설정 > 앱키
: REST API 키 => 복사
|
BACK (백엔드)
📌 보안 설정 : secu.properties
API Key 등 중요한 정보를 secu.properties에 저장하여 관리
1
2
3
4
5
6
| DB_DRIVER=com.mysql.cj.jdbc.Driver
DB_URL=jdbc:mysql://localhost:3306/ureca
DB_USER=ureca
DB_PW=ureca
KAKAO_API_KEY=b343b2cbddccf...
|
📌 환경 변수 읽기 : application.properties
application.properties에서 secu.properties의 KEY를 읽어 오도록 설정한다
1
2
3
4
5
6
7
8
9
10
11
12
13
| spring.application.name=CoffeShop
spring.datasource.driver-class-name=${DB_DRIVER}
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PW}
logging.level.com.shop.cafe=debug
mybatis.type-aliases-package=com.shop.cafe.dto
mybatis.mapper-locations=mapper/*.xml
kakao.api.key=${KAKAO_API_KEY}
|
📌 사용자를 Kakao 인증 화면으로 리디렉트 : OAuthController.java
Kakao 로그인 버튼 클릭 시, kakao OAuth 인증 화면으로 redirect -> 사용자 동의 코드 받기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| @Controller
public class OAuthController {
@Value("${kakao.api.key}")
String KAKAO_API_KEY ;
// Kakao 인증 화면으로 리디렉트
@GetMapping("kakaoLogin")
public String kakaoLogin() {
return "redirect:https://kauth.kakao.com/oauth/authorize?client_id="
+ KAKAO_API_KEY
+ "&redirect_uri=http://localhost:8080/kakaoLoginCallback&response_type=code";
}
// 사용자 동의 후 Kakao에서 code를 반환 & AccessToken 출력
@GetMapping("kakaoLoginCallback")
public String kakaoCallback(@RequestParam String code){
String access_Token = oAuthService.getKaKaoAccessToken(code);
System.out.println("access_Token :" + access_Token );
System.out.println("사용자 동의 코드:" + code);
return null;
}
}
|
📌 동의 코드로 Access Token 요청 : OAuthService.java
kakao에게 동의코드 내밀며 AccessToken 요청하기
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| @Service
public class OAuthService {
@Value("${kakao.api.key}")
String KAKAO_API_KEY ;
public String getKaKaoAccessToken(String code) {
String access_Token = "";
String refresh_Token = "";
String reqURL = "https://kauth.kakao.com/oauth/token";
try {
URL url = new URL(reqURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// POST 요청을 위해 기본값이 false인 setDoOutput을 true로
conn.setRequestMethod("POST");
conn.setDoOutput(true);
// POST 요청에 필요로 요구하는 파라미터 스트림을 통해 전송
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
StringBuilder sb = new StringBuilder();
sb.append("grant_type=authorization_code");
sb.append("&client_id=" + KAKAO_API_KEY );
sb.append("&redirect_uri=http://localhost:8080/kakaoLoginCallback");
sb.append("&code=" + code);
bw.write(sb.toString());
bw.flush();
// 결과 코드가 200이라면 성공
int responseCode = conn.getResponseCode();
System.out.println("responseCode : " + responseCode);
// 요청을 통해 얻은 JSON타입의 Response 메세지 읽어오기
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
String result = "";
while ((line = br.readLine()) != null) {
result += line;
}
System.out.println("response body : " + result);
// Jackson 라이브러리로 JSON 파싱
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(result);
access_Token = jsonNode.get("access_token").asText();
refresh_Token = jsonNode.get("refresh_token").asText();
System.out.println("access_token : " + access_Token);
System.out.println("refresh_token : " + refresh_Token);
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
return access_Token;
}
}
|
📌 kakao에게 AccessToken 내밀며 사용자 정보 요청 : OAuthService.java
Access Token을 사용하여 Kakao에서 사용자 이메일 정보를 가져옴.
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
| public String getKakaoUser(String token) {
String reqURL = "https://kapi.kakao.com/v2/user/me";
String email = "";
try {
URL url = new URL(reqURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer " + token);
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String result = br.readLine();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(result);
boolean hasEmail = jsonNode.get("kakao_account").get("has_email").asBoolean();
if (hasEmail) {
email = jsonNode.get("kakao_account").get("email").asText();
}
System.out.println("email : " + email);
br.close();
} catch (IOException e) {
e.printStackTrace();
}
return email;
}
|
📌 Access Token과 이메일 출력 : OAuthController.java
1
2
3
4
5
6
7
8
9
10
11
12
| @GetMapping("kakaoLoginCallback")
public String kakaoCallback(@RequestParam String code) {
System.out.println("사용자 동의 코드:" + code);
String access_Token = oAuthService.getKaKaoAccessToken(code);
System.out.println("access_Token :" + access_Token);
String email = oAuthService.getKakaoUser(access_Token);
System.out.println("email :" + email);
return null;
}
|
📌 Access Token과 Email을 쿠키에 저장 : OAuthController.java
OAuthController.java
에서 email과 AccessToken을 쿠키로 설정해서 kakao 서버로 리턴하면 kakao에서 클라이언트로 redirect page를 보내준다. 이때 클라이언트 브라우저에 쿠키가 저장된다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| @GetMapping("kakaoLoginCallback")
public String kakaoCallback(@RequestParam String code, HttpServletResponse response) {
String access_Token = oAuthService.getKaKaoAccessToken(code);
String email = oAuthService.getKakaoUser(access_Token);
if (email != null) {
Cookie c1 = new Cookie("email", email);
Cookie c2 = new Cookie("Authorization", access_Token);
response.addCookie(c1);
response.addCookie(c2);
}
return "redirect:http://localhost:5500/";
}
|
📌 로그인 정보를 DB에 저장 : OAuthService.java
- 로그인 정보를 DB에 저장하기 위해 insertLoginInfo()라는 메소드를 추가
1
2
3
4
5
6
7
| @Autowired
LoginDao loginDao;
public void insertLoginInfo(String email, String kakaoToken) throws Exception {
Login loginInfo = new Login(email, kakaoToken, null, new Date());
loginDao.insertToken(loginInfo);
}
|
백엔드 흐름
✅ secu.properties로 API Key 보안 관리
✅ application.properties에서 환경 변수 로드
✅ Kakao 로그인 화면으로 리디렉트
✅ 동의 코드(code)를 받아 Access Token 요청
✅ Access Token으로 사용자 정보(이메일) 요청
✅ 이메일과 Access Token을 쿠키에 저장 및 DB에 저장
FRONT (프론트엔드)
index.html : 카카오 로그인
http://localhost:8080/kakaoLogin
으로 이동하여 OAuth 인증 요청
1
2
3
| <a href="http://localhost:8080/kakaoLogin">
<img src="img/kakao.png" width="50">
</a>
|
📌 로그인 요청 후 처리 : member.js
- 카카오 로그인 성공 후 받은 Authorization 토큰을 저장
- 세션 또는 쿠키에서 Authorization이 있으면 자동 로그인 유지
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| let Authorization = sessionStorage.getItem("Authorization");
const nickname = sessionStorage.getItem("nickname");
if (Authorization && nickname) {
axios.defaults.headers.common["Authorization"] = Authorization;
document.getElementById("loginSpan").innerHTML = `${nickname}
<button class="btn btn-danger btn-sm" id="logoutBtn">Logout</button>`;
} else {
Authorization = getCookie("Authorization");
email = getCookie("email");
if (Authorization && email) {
axios.defaults.headers.common["Authorization"] = Authorization;
document.getElementById("loginSpan").innerHTML = `${email}
<button class="btn btn-danger btn-sm" id="logoutBtn">Logout</button>`;
}
}
|
📌 로그아웃 처리
- 카카오 로그아웃 시 세션과 쿠키 초기화 후 페이지 새로고침
1
2
3
4
5
6
7
8
9
10
11
12
13
| document.getElementById("loginSpan").addEventListener("click", async (event) => {
if (event.target.id == "logoutBtn") {
await axios.post("http://localhost:8080/logout");
sessionStorage.removeItem("nickname");
sessionStorage.removeItem("Authorization");
axios.defaults.headers.common["Authorization"] = "";
removeCookie("Authorization");
removeCookie("email");
window.location.reload();
}
});
|
📌 쿠키 관련 유틸리티 함수
- 쿠키에서 Authorization 가져오거나 삭제하는 기능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(";");
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == " ") {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function removeCookie(cname) {
document.cookie = cname + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
}
|
프론트엔드 흐름
1️⃣ 사용자가 카카오 로그인 버튼 클릭 2️⃣ 백엔드(http://localhost:8080/kakaoLogin)로 이동 → OAuth 인증 요청 3️⃣ 카카오에서 인증 후, 백엔드에서 Authorization 토큰 발급 4️⃣ 클라이언트가 sessionStorage 또는 쿠키에 토큰 저장 5️⃣ 이후 페이지 새로고침 시 자동 로그인 유지 6️⃣ 로그아웃하면 세션과 쿠키 삭제 후 새로고침
프로젝트에 적용한 전체 코드 참고
Kakao OAuth
END