9주차 - 3) 소셜 로그인

변현섭·2023년 6월 21일
2

4th UMC Server-Spring Study

목록 보기
28/30

오늘 진행할 실습은 Kakao Login 구현하기입니다. 아래에 작성한 코드를 업로드한 깃허브 링크를 올려놓았으니 참고하시기 바랍니다.
>> 카카오 소셜로그인 깃허브 링크

Ⅲ. 실습

1. Kakao Developers에 애플리케이션 등록하기

1) 애플리케이션 추가하기

https://developers.kakao.com/에 접속한 후 로그인한다.

② 내 애플리케이션 > 애플리케이션 추가를 클릭하면 아래와 같은 창이 나온다.

③ 이미지를 업로드하고 싶으면 해도 되고 안해도 된다.

④ 앱 이름과 사업자명도 임의로 설정해주면 된다.

애플리케이션이 잘 추가된 것을 확인할 수 있을 것이다.

2) Client Id 및 Redirect URI 설정하기

① 생성된 umcLogin을 클릭해 앱 키를 확인할 수 있다. 이중에서 RestAPI의 키를 사용할 예정이니 복사해주어야 한다.

② 좌측 메뉴 > 카카오 로그인을 클릭한 후 활성화 상태를 ON으로 변경한다.

③ 스크롤을 아래로 내려 Redirect URI를 등록한다.

3) 동의 항목(Permission List) 설정하기

좌측 메뉴 > 동의 항목을 클릭한다. 동의 목적 작성란에는 회원 가입이라 적으면 된다.

닉네임과 프로필 사진은 필수적으로 가져오고 카카오계정은 선택적으로 가져오게 하였다.

4) Client Secret 설정하기

필수적으로 해야 하는 것은 아니지만, 권장되는 내용이다. 좌측 메뉴 > 보안 > Client Secret > 코드 생성을 클릭한다. 또한 활성화 상태를 사용함으로 변경한다.

이로써, Kakao Developers에서 해주어야 할 작업은 모두 마무리된다.

2. Kakao API 테스트

Kakao에서 소셜로그인을 편하게 해주기 위한 API를 제공한다. 이를 사용해보기로 하자.

1) Aceess Token 발급받기

① postman에 접속한 후 Get 요청으로, URL은 https://kapi.kakao.com/v2/api/talk/memo/default/send 를 입력해준다.

② Authoriaztion에 들어가서 type을 OAuth 2.0으로 지정한다.

③ Token은 Available Tokens로 하고, Header Prefix는 Bearer로 설정해준다.

④ Token name은 임의로 지정하면 된다. 여기서는 kakaoToken이라고 명명하였다.

⑤ Grant Type은 Authorization Code로 설정하고, Callback URL은 Kakao Developers에서 지정해준 Redirect URI를 넣어주면 된다.

⑥ Auth URL은 https://kauth.kakao.com/oauth/authorize를 넣어주면 되고, Access Token URL은 https://kauth.kakao.com/oauth/token을 넣어주면 된다.

⑦ Client ID는 Kakao Developers에서 받은 Rest API의 키를, Client Secret 역시 Kakao Developers에서 받은 Client Secret 값을 넣어주면 된다.

⑧ 마지막으로, Client Authentication의 설정 값을 Send client credentials in body로 변경해주면 완료된다.

⑨ 스크롤을 아래로 내려 Get New Access Token을 클릭해주자.

정상적으로 완료됐다면, 카카오 로그인창이 나올 것이다.

동의하고 계속하기를 누르면, 아래와 같이 Authentication complete가 나올 것이다. (기존에 로그인을 한 적이 있는 경우에는 바로 Authentication complete가 뜨고, 로그인을 한 적이 없다면 본인의 계정으로 로그인을 해주면 된다.) Proceed 버튼을 누르면 토큰에 대한 정보를 확인할 수 있다.

2) Access Token으로 유저 정보 가져오기

결과창에 나온 Access Token을 복사해두거나, 좌상단에 보이는 Use Token을 눌러주자. Use Token 버튼을 클릭하면, 저절로 Token 값이 입력된다. (직접 ctrl+v하여 입력해도 된다.)

Postman 주소창에 https://kapi.kakao.com/v2/user/me를 입력하고 Header Prefix가 Bearer로 잘 설정되어있는지 확인한 후 Send버튼을 눌러 Get 요청을 보낸다.

결과 창을 자세히 보면 아래와 같다.

보다시피 Permission List에 등록했던 정보들만 응답된다.

3) 연결 끊기

Postman 주소창에 https://kapi.kakao.com/v1/user/unlink를 입력하고 토큰 값을 그대로 유지한 채 Get요청을 보낸다. id만 응답되고 별다른 응답이 나타나지는 않는다.

정말 연결이 끊어졌는지 확인해보기 위해 기존 토큰 그대로 https://kapi.kakao.com/v2/user/me에 Get요청을 다시 보내보자.

토큰이 더 이상 유효하지 않기 때문에 에러가 발생하는 모습이다. 연결이 잘 끊어진 것을 확인할 수 있다.

3. Member 클래스

1) 필드


① refreshToken

  • 멤버의 refreshToken을 저장하는 필드이다.

② accessToken

  • 멤버의 accessToken을 저장하는 필드이다.

③ isSocilaLogin

  • 소셜로그인 여부를 저장하는 필드이다.

④ password

  • 소셜로그인의 경우 password를 입력하지 않기 때문에 nullable 속성을 true로 바꾸어주었다. 단, 일반 로그인의 경우 비밀번호를 입력하지 않으면 가입되지 않도록 별도의 예외처리를 해주어야 한다.
  • 일반 로그인의 경우 password는 null이 될 수 없다는 에러가 발생한다.

2) 메서드


accessToken, refreshToken, IsSocialLogin 필드가 추가된만큼, update메서드도 추가된 모습이다.

4. KakaoController - login

1) @ResponseBody

HTTP 응답을 생성할 때, 해당 메서드의 반환 값을 HTTP 응답의 본문으로 사용하도록 지정하는 어노테이션이다.

2) getMemberEmail

① HttpHeaders 객체를 생성하고, 헤더에 Authorization 필드와 Content-type을 추가한다. 사실 여기에는 body에 입력해줄 데이터가 없기 때문에 Content-type은 생략해도 된다. 참고로 Bearer는 OAuth 2.0에서 사용하는 인증 방식 중 하나로 액세스 토큰을 식별하기 위한 키워드이다.

② HttpEntity 클래스는 HTTP 요청 또는 응답의 헤더와 바디 정보를 포함하는 객체이다. 그러므로 requestEntity 객체는 Http요청을 보낼 때 사용할 헤더 정보와 바디 정보를 모두 담기 위해 사용되었다.

③ 하지만, 여기서는 바디 정보는 포함하지 않고 헤더 정보만 갖고 있다. 만약 바디 정보도 포함해야 할 경우에는 HttpEntity 생성자의 두번째 매개변수에 httpBody의 정보를 추가해주어야 한다. HttpEntity<String>에서 String이라는 Generics는 무의미한 값이다. Generics에는 요청 본문의 타입이 담기는데, 여기서는 요청 본문이 비어있으므로 그냥 빈 문자열이라는 뜻에서 String을 쓴 것 뿐이다.

④ RestTemplate의 객체를 생성함으로써 브라우저 없이 Http 요청을 처리할 수 있게 해주었다.

⑤ RestTemplate의 exchange 메서드를 이용하여 "https://kapi.kakao.com/v2/user/me" URL로 GET 방식의 HTTP 요청을 실행하고 있다. HTTP 요청에는 requestEntity가 포함되어 있으며 이에 대한 응답은 String형이다(왜 String인지는 ⑥ 참조). 여기서 말하는 응답이란, HTTP 상태코드, 헤더, 바디 데이터 등이다. 이를 받아줄 수 있는 자료형이 ResponseEntity인 것이다.

⑥ responseEntity는 Http응답을 나타낸다. JSON 형식의 응답을 String으로 받은 이유는 .getBody를 사용하여 응답의 body 데이터를 String으로 가져오기 위해서이다. 우리가 카카오 API를 통해 액세스토큰으로 가져왔던 유저 정보가 이에 해당한다

⑦ Gson 객체를 만든다. Gson이란, JSON 데이터를 다루기 위해 사용되는 라이브러리이다. gsonObj.fromJson메서드를 통해 memberInfo 문자열을 Map 객체로 변환한다. 여기서 ?는 와일드카드로써, 다양한 타입의 요소를 포함할 수 있다. 즉, 키와 값의 타입이 명시되지 않는 맵인 것이다. 유저의 정보에는 id 같은 정수도 있고, nickname 같은 String도 있으며, 동의사항 같은 boolean도 있기 때문에 와일드카드를 사용해주었다.

⑧ Map에서 id와 email을 추출하고 있다. Map의 key와 value의 형식을 지정해주지 않았기 때문에 반드시 직접 캐스팅해주어야 한다. 여기서 id는 사용되진 않지만 참고로 넣어두었다. 또한 카카오 API에서 유저 정보를 가져왔던 부분을 다시 보면, email 값은 kakao_account 안에 key-value 형태로 존재하고 있다. 이를 가져오기 위해선 map에서 kakao_account 키로 get한 값에 다시 email을 key로 get해주어야 한다.

3) getMemberNickName

① httpHeaders.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); 는 마찬가지로 생략 가능하다.

② 닉네임은 properties 안에 있기 때문에 map에서 properties 키로 get한 값에 다시 nickname을 key로 get해주어야 한다.

4) if-else 문

① if 문

  • getMemberEmail로 가져온 이메일이 memberRepository에 존재하지 않는 경우, 멤버의 email, nickname, isSocialLogin, accessToken, refreshToken을 설정하고 멤버를 memberRepository에 save한다.
  • 유저의 accessToken, refreshToken의 값을 반환한다.

② else 문

  • findMember는 Optinal타입이기 때문에 만약 null이 입력되었을 때 get메서드를 사용하면 NPE(Null Pointer Exception)가 발생한다. 하지만, 이미 else 문을 통해 멤버저장소에 존재하는 값임을 확인했기 때문에 get으로 member를 받아줄 수 있다.
  • 이미 존재하는 멤버인 경우에는 refreshToken을 새로 발급해주는 것만으로 로그인을 유지 및 갱신할 수 있다.
  • generateToken 메서드는 accessToken과 refreshToken을 생성하는 메서드로, 아래와 같이 정의되었다. setHeaderParam(Header.TYPE, Header.JWT_TYPE)은 JWT 헤더를 설정한다. JWT 헤더에는 일반적으로 alg(algorithm)이나 typ(type)이 포함되는데, 이 중 typ필드를 Header.JWT_TYPE으로 설정한 것이다. 여기서 Header.JWT_TYPE은 JWT로 정의되어 있다. 즉, Header.TYPE은 key이고, Header.JWT_TYPE은 value로, 해당 토큰이 JWT임을 명시하고 있다.

5) JwtResponseDTO


accessToken과 refreshToken를 담은 TokenInfo를 저장하는 DTO이다. 이를 이용해 member의 accessToken과 refreshToken 값을 입력하고 있다. update를 한 이후에는 반드시 memberRepository에 저장해야 영속성이 유지될 수 있다.

5. KakaoController - logout


memberService의 logout 메서드는 아래와 같이 정의되었다.

responseEntity의 상태코드가 HttpStatus.OK이면 즉, 요청에 성공했으면 로그아웃에 성공한 것이다. 반대로 어떠한 이유에서든 상태코드가 HttpStatus.OK아니면 요청에 실패한 것으로, 로그아웃에 실패한 것이다.

profile
Java Spring, Android Kotlin, Node.js, ML/DL 개발을 공부하는 인하대학교 정보통신공학과 학생입니다.

0개의 댓글