참고 블로그 : https://cdi3124.tistory.com/77
이번 프로젝트에는 저번에 못했던 카카오 소셜 로그인을 구현해 보았습니다. 생각보다 어려웠습니다 ㅎㅎ;;;;;;;
다음에 쉽게 사용할 수 있도록 기록해 봅니다.
~~ 카카오 소셜로그인 절차 ~~
우선 카카오 소셜 로그인 절차를 알아보겠습니다.
카카오에서 제공하는 문서에도 상세하게 나와있습니다.
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-token
카카오 소셜 로그인 API로 사용자의 정보를 받으려면 인가 코드를 받아서 토큰을 발급받아야 하고 토큰을 이용하여 사용자 정보를 요청해야 합니다.
https://kauth.kakao.com/oauth/authorize?client_id= {REST_API_KEY}&redirect_uri={REDIRECT_URI}&response_type=code
- 위 주소는 인가 코드를 받기 위한 주소입니다. client_id, redirect_uri을 파라미터로 보내야 합니다. 카카오에 GET방식으로 요청합니다.
- 카카오는 사용자에게 로그인과 동의 항목에서 설정한 항목들을 동의할 건지 물어보고 사용자가 로그인과 동의를 끝내면 우리가 파라미터로 보낸 redirect_uri에 code를 전달해 줍니다.
- 받은 code를 controller에서 파라미터로 받아서 service에 전달합니다.
- service단에서 https://kauth.kakao.com/oauth/token에 POST방식으로 토큰을 요청합니다.
- 위 사진은 토큰을 받기 위해 전달해야 하는 파라미터입니다.
grant_type=authorization_code&client_id=~~~&redirect_uri=~~~&code=~~~
- 위 사진은 요청 성공 시 카카오가 응답하는 토큰과 토큰 정보입니다.
- ── 이후의 설명은 필요한 로그인 절차에 따라 달라질 수 있습니다. ──
- 받은 토큰으로 사용자의 정보를 받습니다. (getUserInfo 메드)
- 사용자의 정보를 JSON 파싱 합니다.
- 파싱한 정보를 HashMap에 담아서 이 정보를 가진 사용자가 회원 목록에 있는지 확인합니다.
- 회원 목록에 있다면 사용자 정보를 controller로 반환하고 로그인 처리합니다.
- 회원 목록에 없다면 회원가입 후 사용자 정보를 controller로 반환고 로그인 처리합니다.
1. Kakao Developers 회원가입 / 로그인
카카오 소셜로그인 API를 이용하기 위해서 Kakao Developers 회원가입이 필요합니다.
2. 내 애플리케이션 > 애플리케이션 추가하기
입력된 정보는 사용자가 카카오 로그인을 할 때 표시됩니다. 앱 이름과 사업자명은 아무거나 입력해도 된다고 하던데 저는 프로젝트 명으로 입력했습니다.
3. 도메인, Redirect URI 등록
추가된 애플리케이션 > 플랫폼 > WEB > 도메인 등록
하단에 Redirect URI 등록하러 가기 버튼 클릭
활성화 ON으로 변경, Redirect URI는 본인이 사용할 매핑 주소 입력하면 됩니다.
4. 동의항목 설정
카카오 로그인으로 사용자에게 받을 정보의 동의 항목 설정
저는 닉네임과 이메일을 추가했습니다. 이메일을 필수로 가져오려면 유료 비즈니스 설정을 이용해야 합니다.
5. Gson 라이브러리 추가
Json을 파싱하기 위해서 pom.xml에 dependency를 추가합니다.
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
6. JSP 화면
<a href="/member/kakao_oauth">
<img class="" src="/resources/include/images/kakao_login_large_wide.png">
</a>
버튼 이미지는 https://developers.kakao.com/docs/latest/ko/kakaologin/design-guide에서 다운로드 할 수 있습니다.
7. controller
@RequestMapping(value="/kakao_oauth", method=RequestMethod.GET)
public String kakaoOauth(HttpServletResponse response) {
StringBuffer url = new StringBuffer();
url.append("https://kauth.kakao.com/oauth/authorize?");
url.append("client_id=***본인의 client_id***");
url.append("&redirect_uri=***본인의 redirect_uri***");
url.append("&response_type=code");
System.out.println("kakao url " + url);
return "redirect:" + url;
}
@RequestMapping(value="/kakao_login", method=RequestMethod.GET)
public String kakaoCallback(@RequestParam String code, HttpServletRequest request) {
// 인가코드 보내서 토큰 받기
String access_Token = memberService.getAccessToken(code);
// 토큰을 보내서 사용자 정보 받기
MemberVO member = memberService.getUserInfo(access_Token);
HttpSession session = request.getSession();
session.setAttribute("member", member);
session.setMaxInactiveInterval(-1); // 세션 시간을 무한대로 설정
String prevPage = (String) request.getSession().getAttribute("prevPage");
log.info(prevPage);
if (prevPage != null && !prevPage.equals("")) {
request.getSession().removeAttribute("prevPage");
// 회원가입 - 로그인으로 넘어온 경우 "/"로 redirect
if (prevPage.contains("/member/join")) {
return "redirect:/";
} else {
return "redirect:" + prevPage;
}
} else return "redirect:/";
}
client_id에는 앱 키에서 REST API 키를 복사하여 넣어주세요.
redirect_uri는 여기서 작성한 URI를 입력하세요.
8. Service / ServiceImpl
public interface MemberService {
// 카카오 토큰 받기
public String getAccessToken(String code);
// 카카오 로그인 정보 저장
public MemberVO getUserInfo(String access_Token);
}
@Service
public class MemberServiceImpl implements MemberService {
@Autowired
private MemberDAO memberDao;
// 카카오 토큰 받기
@Override
public String getAccessToken(String code) {
String access_Token = "";
String refresh_Token = "";
String reqURL = "https://kauth.kakao.com/oauth/token";
try {
// url 객체 생성
URL url = new URL(reqURL);
// url에서 url connection 객체 얻기
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// setRequestMethod : HTTP 메소드 설정, 기본값은 GET
conn.setRequestMethod("POST");
// setDoOutput : urlconnection이 서버에 데이터를 보낼 수 있는지 여부 설정, 기본값 false
conn.setDoOutput(true);
// POST 요청에 필요로 요구하는 파라미터 스트림을 통해 전송
// POST로 보낼 Body 작성
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
StringBuilder sb = new StringBuilder();
sb.append("grant_type=authorization_code");
sb.append("&client_id=본인이 발급받은 key");
sb.append("&redirect_uri=http://localhost:8080/member/kakao_login"); // 본인이 설정한 주소
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);
// Gson 라이브러리에 포함된 클래스로 JSON파싱 객체 생성
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(result);
access_Token = element.getAsJsonObject().get("access_token").getAsString();
refresh_Token = element.getAsJsonObject().get("refresh_token").getAsString();
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;
}
// 카카오 회원 정보 받기
@Override
public MemberVO getUserInfo(String access_Token) {
// 요청하는 클라이언트마다 가진 정보가 다를 수 있기에 HashMap타입으로 선언
HashMap<String, Object> userInfo = new HashMap<String, Object>();
String reqURL = "https://kapi.kakao.com/v2/user/me";
try {
URL url = new URL(reqURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + access_Token);
int responseCode = conn.getResponseCode();
System.out.println("responseCode : " + responseCode);
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);
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(result);
JsonObject properties = element.getAsJsonObject().get("properties").getAsJsonObject();
JsonObject kakao_account = element.getAsJsonObject().get("kakao_account").getAsJsonObject();
String nickname = properties.getAsJsonObject().get("nickname").getAsString();
String email = kakao_account.getAsJsonObject().get("email").getAsString();
// email에서 @의 앞부분을 id로 설정
String[] id = email.split("@");
userInfo.put("user_id", id[0]);
userInfo.put("user_name", nickname);
userInfo.put("email", email);
} catch (IOException e) {
e.printStackTrace();
}
// 회원 정보가 있는지 확인
MemberVO result = memberDao.findKakao(userInfo);
// 회원 정보 없을 때
if(result == null) {
memberDao.kakaoInsert(userInfo);
return memberDao.findKakao(userInfo);
} else {
return result; // 회원 정보 있으면 회원 정보 리턴
}
}
9. DAO
public interface MemberDAO {
// 카카오로 받은 정보가 회원목록에 있는지 확인
public MemberVO findKakao(HashMap<String, Object> userInfo);
// 카카오 회원 정보 저장
public void kakaoInsert(HashMap<String, Object> userInfo);
}
9. mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jam.client.member.dao.MemberDAO">
<!-- 카카오 정보 찾기 -->
<select id="findKakao" parameterType="java.util.HashMap" resultType="member">
<![CDATA[
select *
from member
where user_name=#{user_name} and email=#{email}
]]>
</select>
<!-- 카카오 회원 정보 저장 -->
<insert id="kakaoInsert" parameterType="java.util.HashMap">
INSERT INTO member (user_id, user_name, email)
VALUES (#{user_id}, #{user_name}, #{email})
</insert>
</mapper>
로그인 아주 잘 됨!
'프로젝트 > JAM' 카테고리의 다른 글
---- (0) | 2024.02.05 |
---|---|
-- (0) | 2023.12.04 |
[SpringMVC] Spring Security + JWT토큰 (1) | 2023.10.03 |
[Spring] Spring Security (0) | 2023.09.02 |
[Spring] 네이버 소셜 로그인 구현 REST API (0) | 2023.08.24 |