Bank 카카오 소셜로그인 처리

1. 작업 순서

Auth 2.0

  1. 내 애플리케이션 항목에 등록
    (로그인) - (kakao developers내 애플리케이션 등록)
  2. 플랫폼(web 선택) - 사이트 도메인 기본설정
    - http://localhost:8080
  3. 카카오 로그인 사용 시 Redirect URI를 등록
    - 활성화 ON 처리
    - http://localhost:8080/user/kakao (리다이렉트 URI 설정)
  4. 동의 항목 설정(제품설정--동의항목 왼쪽 메뉴)
    - 닉네임, 프로필 사진
  5. 리소스 다운로드
    - 도구 --> 리소스다운로드 --> 카카오로그인
  6. REST API 키 - API키
    ------------------------------------------
  7. 인가 코드 받기
    https://kauth.kakao.com/oauth/authorize?response_type=code&client_id="API키"&redirect_uri=http://localhost:8080/user/kakao
    7-1 . 콜백 메서드 구현 (UserController)
  8. 토큰 받기
    POST
    https://kauth.kakao.com/oauth/token

    응답 결과
    {"access_token":" access_token 값","token_type":"bearer","refresh_token":" refresh_token 값","expires_in":21599,"scope":"profile_image profile_nickname","refresh_token_expires_in":5183999}
    - DTO JSON 파싱 처리 완료
  9. 사용자 정보 가져오기
    GET/POST
    https://kapi.kakao.com/v2/user/me
    인증방식
    - 만들었던 OAuthToken.getAccessToken();
    https://kapi.kakao.com/v2/user/me?secure_resource=true

2. UserController 코드 추가

@GetMapping("/kakao")
// @ResponseBody // @RestControler = @Controller + @ResposeBody 
public String getMethodName(@RequestParam(name = "code") String code) {
    System.out.println("code : " + code);

    // POST - 카카오 토큰 요청 받기 
    // Header, body 구성 
    RestTemplate rt1 = new RestTemplate();
    // 헤더 구성 
    HttpHeaders header1 = new HttpHeaders();
    header1.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
    // 바디 구성 
    MultiValueMap<String, String> params1 = new LinkedMultiValueMap<String, String>();
    params1.add("grant_type", "authorization_code");
    params1.add("client_id", "");
    params1.add("redirect_uri", "http://localhost:8080/user/kakao");
    params1.add("code", code);

    // 헤더 + 바디 결합 
    HttpEntity<MultiValueMap<String, String>> reqkakoMessage 
        = new HttpEntity<>(params1, header1);  

    // 통신 요청 
    ResponseEntity<OAuthToken> response1	=  rt1.exchange("https://kauth.kakao.com/oauth/token", 
            HttpMethod.POST, reqkakoMessage, OAuthToken.class);
    System.out.println("response : " + response1.getBody().toString());

    // 카카오 리소스서버 사용자 정보 가져오기 
    RestTemplate rt2 = new RestTemplate();
    // 헤더 
    HttpHeaders headers2 = new HttpHeaders();
    // 반드시 Bearer 값 다음에 공백 한칸 추가 !! 
    headers2.add("Authorization", "Bearer " +response1.getBody().getAccessToken());
    headers2.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
    // 본문 x 

    // HTTP Entity 만들기 
    HttpEntity<MultiValueMap<String, String>> reqKakoInfoMessage = new HttpEntity<>(headers2);

    // 통신 요청 
    ResponseEntity<KakaoProfile> resposne2 = 
                rt2.exchange("https://kapi.kakao.com/v2/user/me", HttpMethod.POST, 
                reqKakoInfoMessage, KakaoProfile.class);

    KakaoProfile kakaoProfile = resposne2.getBody();
    // ---- 카카오 사용자 정보 응답 완료 ----------

    // 최초 사용자라면 자동 회원 가입 처리 (우리 서버) 
    // 회원가입 이력이 있는 사용자라면 바로 세션 처리 (우리 서버) 
    // 사전기반 --> 소셜 사용자는 비밀번호를 입력하는가? 안하는가? 
    // 우리서버에 회원가입시에 --> password -> not null (무건 만들어 넣어야 함 DB 정책) 

    // 1.회원가입 데이터 생성 
    SignUpDTO signUpDTO = SignUpDTO.builder()
            .username(kakaoProfile.getProperties().getNickname() 
                    + "_" + kakaoProfile.getId())
            .fullname("OAuth_" + kakaoProfile.getProperties().getNickname())
            .password(tencoKey)
            .build();

    // 2.우리사이트 최초 소셜 사용자 인지 판별 
    User oldUser = userService.searchUsername(signUpDTO.getUsername());
    // select * from user_tb where username = ?
    if(oldUser == null) {
        // 사용자가 최초 소셜 로그인 사용자 임
        oldUser = new User();
        oldUser.setUsername(signUpDTO.getUsername());
        oldUser.setPassword(null);
        oldUser.setFullname(signUpDTO.getFullname());
        userService.createUser(signUpDTO);
    }

    // 프로필 이미지 여부에 따라 조건식 추가 
    signUpDTO.setOriginFileName(kakaoProfile.getProperties().getThumbnailImage());
    oldUser.setUploadFileName(kakaoProfile.getProperties().getThumbnailImage());

    // 자동 로그인 처리
    session.setAttribute(Define.PRINCIPAL, oldUser);
    return "redirect:/account/list";
}

3. 추가 코드

OAuthToken 코드 생성
package com.tenco.bank.dto;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import lombok.Data;
import lombok.ToString;

// JSON 형식에 코딩 컨벤션이 스네이크 케이스를 카멜 노테이션으로 할당하라! 
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@ToString
public class OAuthToken {

    private String accessToken;
    private String tokenType;
    private String refreshToken;
    private Integer expiresIn;
    private String scope;
    private Integer refreshTokenExpiresIn;
	
}
yml 추가
# 초기 파라메터 설정 
file:
  upload-dir: C:\\work_spring\\upload/

tenco:
  key: api키
  • 사용
@Controller  
@RequestMapping("/user")  
@RequiredArgsConstructor
public class UserController {
	
	@Autowired
	private final UserService userService;
	private final HttpSession session;
	
	@Value("${tenco.key}")
	private String tencoKey; 
	
	// ... 생략
KakaoProfile 코드 추가
package com.tenco.bank.dto;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import lombok.Data;
import lombok.ToString;

@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@ToString
public class KakaoProfile {
	private Long id; 
	private String connectedAt; 
	private Properties properties;
}
UserService 코드 추가
/**
 * username 사용자 존재 여부 조회 
 * @param String username 
 * @return User, null 
 */
public User searchUsername(String username) {
    return userRepository.findByUsername(username);
}