My Proect/파이널 프로젝트 - CineDate

10일차 - 소셜 로그인 API 구현 ( 구글, 네이버, 카카오 )

형디 2024. 9. 3. 12:04

[ 구글 ]

 

 

signIn.jsp - 구글, 카카오, 네이버
<div class="social--login">
    <div class="social--google btn">
    	<a href="https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?client_id=973551558208-05iorgfbtui4jkb49on38lpuv0o13jf5.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fuser%2Fgoogle&response_type=code&scope=email profile&service=lso&o2v=2&ddm=1&flowName=GeneralOAuthFlow"><img src="/img/google.png" alt="구글로 시작하기"></a>
    </div>
    <div class="social--kakao btn">
    	<a href="https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=75ba363608bd6f2a3cfbf6acaf901f10&redirect_uri=http://localhost:8080/user/kakao"><img src="/img/kakao.png" alt="카카오로 시작하기"></a>
    </div>
				
    <div class="social--naver btn" id="naver_id_login">
    	<a href="https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=fLZ62UlS4udx_2KU4B4r&state=test&redirect_uri=http://localhost:8080/user/naver"><img src="/img/naver.png" alt="네이버로 시작하기"></a>
    </div>
</div>

 

 

 

user.xml
<!-- 구글로 로그인 -->
<insert id="googleInsert">
	insert into user_tb(login_id, name, password, email)
	values(#{loginId}, #{name}, #{password}, #{email})
</insert>
	
<!-- 네이버로 로그인 -->
<insert id="naverInsert">
	insert into user_tb(login_id, name, password, email, phone_num, birth_day, gender)
	values(#{loginId}, #{name}, #{password}, #{email}, #{phoneNum}, #{birthDay}, #{gender})
</insert>
	
<!-- 카카오로 로그인 -->
<insert id="kakaoInsert">
	insert into user_tb(login_id, name, password)
	values(#{loginId}, #{name}, #{password})
</insert>

 

 

 

GoogleProfile
package com.tenco.movie.dto;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.tenco.movie.repository.model.User;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@JsonNaming(value=PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
public class GoogleProfile {
	
	private String id;
	private String name;
	private String email;
	private boolean verifiedEmail;
	private String givenName;
	private String familyName;
	private String picture;
	private String laclae;
	
	public User googleUser() {
		return User.builder()
				.loginId(id)
				.name(name)
				.password(id)
				.email(email)
				.build();
	}
	
}

 

 

 

GoogleOAuthToken
package com.tenco.movie.dto;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.tenco.movie.repository.model.User;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@JsonNaming(value=PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
public class GoogleOAuthToken {
	
	private String accessToken;
	private String expiresIn;
	private String scope;
	private String tokenType;
	private String idToken;

}

 

 

 

UserController
/**
	 * 구글 로그인
	 * @param code
	 * @return
	 */
	@GetMapping("/google")
	public String google(@RequestParam(name = "code") String code) {
		
		System.out.println("code : " + code);
		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<>();
		
		// 구글 시크릿 코드 및 add 자리
		params1.add("code", code);
		params1.add("client_id", "");
		params1.add("client_secret", "");
		params1.add("redirect_uri", "http://localhost:8080/user/google");
		params1.add("grant_type", "authorization_code");
		
		HttpEntity<MultiValueMap<String, String>> reqGoogleMessage = new HttpEntity<>(params1, header1);

		ResponseEntity<GoogleOAuthToken> response1 = rt1.exchange("https://oauth2.googleapis.com/token", HttpMethod.POST,reqGoogleMessage, GoogleOAuthToken.class);

		System.out.println("GoogleAuthToken : " + response1.getBody().toString());

		RestTemplate rt2 = new RestTemplate();

		HttpHeaders headers2 = new HttpHeaders();

		headers2.add("Authorization", "Bearer " + response1.getBody().getAccessToken());
		headers2.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");

		HttpEntity<MultiValueMap<String, String>> reqGoogleInfoMessage = new HttpEntity<>(headers2);

		ResponseEntity<GoogleProfile> response2 = rt2.exchange("https://www.googleapis.com/userinfo/v2/me", HttpMethod.GET, reqGoogleInfoMessage, GoogleProfile.class);

		System.out.println("googleProfile : " + response2.getBody().toString());
		
		GoogleProfile profile = response2.getBody(); 

		User oldUser = userService.searchLoginId(profile.getId());
		
		System.out.println("oldUser : " + oldUser);
		if(oldUser == null) {
			oldUser = new User();
			oldUser.setLoginId(profile.googleUser().getLoginId());
			oldUser.setPassword(profile.googleUser().getLoginId());

			userService.createGoogleUser(profile);
			
		}
		session.setAttribute(Define.PRINCIPAL, oldUser);
		
		return "redirect:/home";
	}

 

 

 

UserService
/**
	 * 카카오 로그인
	 * @param dto
	 */
	@Transactional
	public void createKakaoUser(SignUpDTO dto) {

		int result = 0;

		try {
			result = userRepository.kakaoInsert(dto.kakaoUser());
		} catch (DataDeliveryException e) {
			throw new DataDeliveryException(Define.DUPLICATION_NAME, HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			throw new RedirectException(Define.UNKNOWN_ERROR, HttpStatus.SERVICE_UNAVAILABLE);
		}

		if (result != 1) {
			throw new DataDeliveryException(Define.FAIL_TO_CREATE_USER, HttpStatus.INTERNAL_SERVER_ERROR);
		}

	}

 

 

 


 

 

[ 네이버 ]

 

 

 

NaverOAuthToken
package com.tenco.movie.dto;

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

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@JsonNaming(value=PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class NaverOAuthToken {

	private String accessToken;
	private String refreshToken;
	private String tokenType;
	private Integer expiresIn;
	private String error;
	private String errorDescription;
	
}

 

 

 

 

NaverProfile
package com.tenco.movie.dto;

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

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@JsonNaming(value=PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
public class NaverProfile {

	private String resultcode;
	private String message;
	private NaverProfileResponse response;

}

 

 

 

NaverProfileResponse
package com.tenco.movie.dto;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.tenco.movie.repository.model.User;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@JsonNaming(value=PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
public class NaverProfileResponse {

	private String id;
	private String nickname;
	private String name;
	private String email;
	private String gender;
	private String age;
	private String birthday;
	private String profileImage;
	private String birthyear;
	private String mobile;
	
	public User naverUser() {
		return User.builder()
				.loginId(id)
				.name(name)
				.password(id)
				.email(email)
				.phoneNum(mobile)
				.birthDay(birthyear + "-" + birthday)
				.gender(getGenderDisplay())
				.build();
	}
	
	public String getGenderDisplay() {
        if (gender == null) {
            return "Unknown";
        }
        return gender.equals("F") ? "여" : "남";
    }
	
	
}

 

 

 

 

NaverAuthority
package com.tenco.movie.dto;

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

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@JsonNaming(value=PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class NaverAuthority {

	private String resultcode;
	private String message;
	private NaverAuthorityResponse response;

}

 

 

 

 

NaverAuthorityResponse
package com.tenco.movie.dto;

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

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@JsonNaming(value=PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class NaverAuthorityResponse {
	
	private String token;
	private String expireDate;
	private String allowedProfile;

}

 

 

 

 

UserService
/**
	 * 네이버 로그인 기능
	 * @param dto
	 */
	@Transactional
	public void createNaverUser(NaverProfileResponse dto) {

		int result = 0;

		try {
			result = userRepository.naverInsert(dto.naverUser());
		} catch (DataDeliveryException e) {
			throw new DataDeliveryException(Define.DUPLICATION_NAME, HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			throw new RedirectException(Define.UNKNOWN_ERROR, HttpStatus.SERVICE_UNAVAILABLE);
		}

		if (result != 1) {
			throw new DataDeliveryException(Define.FAIL_TO_CREATE_USER, HttpStatus.INTERNAL_SERVER_ERROR);
		}

	}

 

 

 

 

 

UserController
/**
	 * 네이버 로그인
	 * @return
	 */
	@GetMapping("/naver")
	public String naver(@RequestParam(name = "code") String code, @RequestParam(name = "state") String state) {
	
		System.out.println("code : " + code);
		System.out.println("state : " + state);
		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<>();
		params1.add("grant_type", "");
		params1.add("client_id", "");
		params1.add("client_secret", "");
		params1.add("code", code);
		params1.add("state", state);
		
		HttpEntity<MultiValueMap<String, String>> reqNaverMessage = new HttpEntity<>(params1, header1);

		ResponseEntity<NaverOAuthToken> response1 = rt1.exchange("https://nid.naver.com/oauth2.0/token", HttpMethod.POST,reqNaverMessage, NaverOAuthToken.class);

		System.out.println("NaverOAuthToken : " + response1.getBody().toString());
		
		RestTemplate rt2 = new RestTemplate();

		HttpHeaders headers2 = new HttpHeaders();
		
		headers2.add("Authorization", "Bearer " + response1.getBody().getAccessToken());
		headers2.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");

		HttpEntity<MultiValueMap<String, String>> reqNavernfoMessage = new HttpEntity<>(headers2);

		ResponseEntity<NaverProfile> response2 = rt2.exchange("https://openapi.naver.com/v1/nid/me", HttpMethod.POST, reqNavernfoMessage, NaverProfile.class);

		System.out.println("NaverProfile : " + response2.getBody().toString());
		
		NaverProfile profile = response2.getBody(); 
				
		User oldUser = userService.searchLoginId(profile.getResponse().getId());
		System.out.println(oldUser);
		if(oldUser == null) {
			oldUser = new User();
			oldUser.setLoginId(profile.getResponse().getId());
			oldUser.setPassword(profile.getResponse().getId());

			userService.createNaverUser(profile.getResponse());
			
		}
		session.setAttribute(Define.PRINCIPAL, oldUser);
		
		return "redirect:/home";
		
	}

 

 

 


 

 

 

[ 카카오 ]

 

 

KakaoOAuthToken
package com.tenco.movie.dto;

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

import lombok.Data;

@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
@Data
public class KakaoOAuthToken {

	private String accessToken;
    private String tokenType;
    private String refreshToken;
    private Integer expiresIn;
    private String scope;
    private Integer refreshTokenExpiresIn;
	
}

 

 

 

KakaoProfile
package com.tenco.movie.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;

}

 

 

 

Properties
package com.tenco.movie.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 Properties {
	
	private String nickname;
	private String profileImage;
	private String thumbnailImage;
	private String email;

}

 

 

 

UserController
/**
	 * 카카오 로그인
	 * @param code
	 * @return
	 */
	@GetMapping("/kakao")
	public String kakao(@RequestParam(name = "code") String code) {

		System.out.println("code : " + code);

		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", "");
		params1.add("client_id", "");
		params1.add("redirect_uri", "http://localhost:8080/user/kakao");
		params1.add("code", code);

		HttpEntity<MultiValueMap<String, String>> reqkakaoMessage = new HttpEntity<>(params1, header1);

		ResponseEntity<KakaoOAuthToken> response1 = rt1.exchange("https://kauth.kakao.com/oauth/token", HttpMethod.POST,reqkakaoMessage, KakaoOAuthToken.class);

		System.out.println("response : " + response1.getBody().toString());

		RestTemplate rt2 = new RestTemplate();

		HttpHeaders headers2 = new HttpHeaders();

		headers2.add("Authorization", "Bearer " + response1.getBody().getAccessToken());
		headers2.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");

		HttpEntity<MultiValueMap<String, String>> reqKakaoInfoMessage = new HttpEntity<>(headers2);

		ResponseEntity<KakaoProfile> response2 = rt2.exchange("https://kapi.kakao.com/v2/user/me", HttpMethod.POST, reqKakaoInfoMessage, KakaoProfile.class);

		
		KakaoProfile kakaoProfile = response2.getBody();

		System.out.println("kakaoProfile : " + kakaoProfile);
		
		SignUpDTO signUpDTO = SignUpDTO.builder()
				.loginId(kakaoProfile.getProperties().getNickname() + "_" + kakaoProfile.getId())
				.username(kakaoProfile.getProperties().getNickname())
				.password(tencoKey)
				.email(kakaoProfile.getProperties().getEmail())
				.build();
		
		
		User oldUser = userService.searchUsername(signUpDTO.getUsername());
		if(oldUser == null) {

			oldUser = new User();
			
			signUpDTO.setOriginFileName(kakaoProfile.getProperties().getProfileImage());
			
			userService.createKakaoUser(signUpDTO);
			
			oldUser.setName(signUpDTO.getUsername());
			oldUser.setPassword(null);
			// oldUser.set(signUpDTO.getName());
			
			// 프로필 이미지 여부에 따라 조건식 추가
			signUpDTO.setOriginFileName(kakaoProfile.getProperties().getThumbnailImage());
			userService.createKakaoUser(signUpDTO);
			
		}
		
		// 자동 로그인 처리
		session.setAttribute(Define.PRINCIPAL, oldUser);
		
		return "redirect:/home";
	}

 

 

UserService
/**
	 * 카카오 로그인
	 * @param dto
	 */
	@Transactional
	public void createKakaoUser(SignUpDTO dto) {
		int result = 0;

		try {
			result = userRepository.kakaoInsert(dto.kakaoUser());
		} catch (DataDeliveryException e) {
			throw new DataDeliveryException(Define.DUPLICATION_NAME, HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			throw new RedirectException(Define.UNKNOWN_ERROR, HttpStatus.SERVICE_UNAVAILABLE);
		}

		if (result != 1) {
			throw new DataDeliveryException(Define.FAIL_TO_CREATE_USER, HttpStatus.INTERNAL_SERVER_ERROR);
		}

	}

 

728x90