본문 바로가기

TIL

2022.08.14.TIL

카카오로 로그인하기:

https://developers.kakao.com/console/app

 

카카오계정 로그인

여기를 눌러 링크를 확인하세요.

accounts.kakao.com

애플리케이션 추가하기

플랫폼 등록

사이트 주소, 콜백 주소 설정(https://localhost:8080 , https://localhost:8080/user/kakao/callback)

동의항목 설정

REST API 키 복사

프론트엔드에서 onclick="location.href='https://kauth.kakao.com/oauth/authorize?client_id={내 rest api 키}&redirect_uri={콜백주소}&response_type=code'" 로 버튼생성

 

controller: 

@GetMapping("/user/kakao/callback")
public ResponseDto<?> kakaoLogin(@RequestParam String code, HttpServletResponse response){
  return memberService.kakaoLogin(code, response);
}

@RequestParam에 String code로 받는다.

 

Service:

public ResponseDto<?> kakaoLogin(String code, HttpServletResponse response) {
  try {
    // 1. "인가 코드"로 "액세스 토큰" 요청
    String accessToken = getKakaoAccessToken(code);
    // 2. 토큰으로 카카오 API 호출
    KakoUserInfoDto kakaoUserInfo = getKakaoUserInfo(accessToken);

    // DB 에 중복된 Kakao Id 가 있는지 확인
    Long kakaoId = kakaoUserInfo.getId();
    Member kakaoUser = memberRepository.findByKakaoId(kakaoId)
            .orElse(null);
    if(kakaoUser != null){
      TokenDto tokenDto = tokenProvider.generateTokenDto(kakaoUser);
      tokenToHeaders(tokenDto, response);
      return ResponseDto.success(
              MemberResponseDto.builder()
                      .id(kakaoUser.getId())
                      .username(kakaoUser.getUsername())
                      .nickname(kakaoUser.getNickname())
                      .createdAt(kakaoUser.getCreatedAt())
                      .modifiedAt(kakaoUser.getModifiedAt())
                      .build()
      );
    }
    else{
      // 회원가입
      Member member = Member.builder()
              .username(UUID.randomUUID().toString())
              .nickname(kakaoUserInfo.getNickname())
              .password(passwordEncoder.encode(UUID.randomUUID().toString()))
              .kakaoId(kakaoId)
              .build();
      memberRepository.save(member);
      TokenDto tokenDto = tokenProvider.generateTokenDto(member);
      tokenToHeaders(tokenDto, response);
      return ResponseDto.success(
              MemberResponseDto.builder()
                      .id(member.getId())
                      .username(member.getUsername())
                      .nickname(member.getNickname())
                      .createdAt(member.getCreatedAt())
                      .modifiedAt(member.getModifiedAt())
                      .build()
      );
    }
  }
  catch (JsonProcessingException e){
    return ResponseDto.fail("403","로그인에 실패했습니다.");
  }
}

1. 인가코드로 엑세스 토큰 요청하기

2. 엑세스 토큰으로 사용자 정보 요청하기

3. 사용자정보 활용하기

로 구성된다.

멤버테이블에 카카오로 가입된 계정을 구분하기 위해 카카오아이디(고유번호)를 가져와 kakaoId에 저장하고 일반 로그인 시 kakaoId가 null인 경우에만 로그인이 되도록 함.

해당 kakaoId가 이미 테이블에 존재하면 토큰을 생성 후 로그인 처리,

해당 kakaoId가 존재하지 않으면 UUID로 아이디와 패스워드에 랜덤값을 준 뒤 닉네임, kakaoId와 함께 멤버 테이블에 저장 후 토큰 발급+로그인

 

인가코드로 엑세스 토큰 요청하기:

private String getKakaoAccessToken(String code) throws JsonProcessingException {
  // HTTP Header 생성
  HttpHeaders headers = new HttpHeaders();
  headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");

  // HTTP Body 생성
  MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
  body.add("grant_type", "authorization_code");
  body.add("client_id", "2b986d1b574416a7d6d064619545aaff");//내 api키
  body.add("redirect_uri", "http://localhost:8080/user/kakao/callback");
  body.add("code", code);//카카오로부터 받은 인가코드

  // HTTP 요청 보내기
  HttpEntity<MultiValueMap<String, String>> kakaoTokenRequest =
          new HttpEntity<>(body, headers);//httpentity객체를 만들어서 보냄
  RestTemplate rt = new RestTemplate();//서버 대 서버 요청을 보냄
  ResponseEntity<String> response = rt.exchange(
          "https://kauth.kakao.com/oauth/token",
          HttpMethod.POST,
          kakaoTokenRequest,
          String.class
  );//리스폰스 받기

  // HTTP 응답 (JSON) -> 액세스 토큰 파싱
  String responseBody = response.getBody();//바디부분
  ObjectMapper objectMapper = new ObjectMapper();
  JsonNode jsonNode = objectMapper.readTree(responseBody);//json형태를 객체형태로 바꾸기
  return jsonNode.get("access_token").asText();
}

objectMapper.readTree는 JsonProcessingException을 throw해야 함

 

토큰으로 사용자 정보 가져오기:

private KakoUserInfoDto getKakaoUserInfo(String accessToken) throws JsonProcessingException {
  // HTTP Header 생성
  HttpHeaders headers = new HttpHeaders();
  headers.add("Authorization", "Bearer " + accessToken);
  headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");

  // HTTP 요청 보내기
  HttpEntity<MultiValueMap<String, String>> kakaoUserInfoRequest = new HttpEntity<>(headers);
  RestTemplate rt = new RestTemplate();//서버 대 서버 요청을 보냄
  ResponseEntity<String> response = rt.exchange(
          "https://kapi.kakao.com/v2/user/me",
          HttpMethod.POST,
          kakaoUserInfoRequest,
          String.class
  );

  String responseBody = response.getBody();
  ObjectMapper objectMapper = new ObjectMapper();
  JsonNode jsonNode = objectMapper.readTree(responseBody);
  Long id = jsonNode.get("id").asLong();
  String nickname = jsonNode.get("properties")
          .get("nickname").asText();

  return new KakoUserInfoDto(id,nickname);
}

정보를 담을 KakaoInfoDto를 만든다.

리퀘스트로 받은 jsonNode에서 필요한 정보를 가져온다.

jsonNode 구조 예시:

{
  "id": 1632335751,
  "properties": {
    "nickname": "르탄이",
    "profile_image": "http://k.kakaocdn.net/...jpg",
    "thumbnail_image": "http://k.kakaocdn.net/...jpg"
  },
  "kakao_account": {
    "profile_needs_agreement": false,
    "profile": {
      "nickname": "르탄이",
      "thumbnail_image_url": "http://k.kakaocdn.net/...jpg",
      "profile_image_url": "http://k.kakaocdn.net/...jpg"
    },
    "has_email": true,
    "email_needs_agreement": false,
    "is_email_valid": true,
    "is_email_verified": true,
    "email": "letan@sparta.com"
  }
}

더 자세한 내용: https://developers.kakao.com/docs/latest/ko/kakaologin/common

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

깃 포크, 풀 리퀘스트 활용해보기:

1. 가져올 깃 프로젝트에서 상단 우측 fork눌러서 내 리포지토리에 복사

2. 새 브랜치 생성 후 메인 브랜치 내용 복사

3. 메인 브랜치는 싱크만 하고 새 브랜치에서 작업

4. 메인브랜치 싱크 후 새브랜치와 병합하며 conflict 처리

5. full request전달

6. 메인 깃 프로젝트 소유자가 전달된 full request확인 후 merge

'TIL' 카테고리의 다른 글

2022.08.16.TIL  (0) 2022.08.16
2022.08.15.TIL  (0) 2022.08.15
2022.08.11.TIL  (0) 2022.08.11
2022.08.09.TIL  (0) 2022.08.09
2022.08.08.TIL  (0) 2022.08.08