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