KaKaoLogin.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. package com.style24.front.biz.thirdparty;
  2. import com.gagaframework.web.parameter.GagaMap;
  3. import com.gagaframework.web.util.GagaFileUtil;
  4. import com.google.gson.Gson;
  5. import com.google.gson.GsonBuilder;
  6. import com.google.gson.JsonObject;
  7. import com.google.i18n.phonenumbers.PhoneNumberUtil;
  8. import com.google.i18n.phonenumbers.Phonenumber;
  9. import com.style24.core.support.env.TscConstants;
  10. import com.style24.front.support.security.session.TsfSession;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.apache.commons.lang3.StringUtils;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.beans.factory.annotation.Value;
  15. import org.springframework.core.env.Environment;
  16. import org.springframework.http.HttpEntity;
  17. import org.springframework.http.HttpHeaders;
  18. import org.springframework.http.MediaType;
  19. import org.springframework.http.ResponseEntity;
  20. import org.springframework.stereotype.Component;
  21. import org.springframework.util.LinkedMultiValueMap;
  22. import org.springframework.util.MultiValueMap;
  23. import org.springframework.web.client.RestTemplate;
  24. import com.vdurmont.emoji.EmojiParser;
  25. import javax.annotation.PostConstruct;
  26. import java.net.URI;
  27. import java.util.Locale;
  28. /**
  29. * 카카오 로그인
  30. *
  31. * @author jsshin
  32. * @since 2021. 02. 05
  33. */
  34. @Component
  35. @Slf4j
  36. public class KaKaoLogin {
  37. @Autowired
  38. private Environment env;
  39. @Autowired
  40. private RestTemplate restTemplate;
  41. @Value("${has-ssl}")
  42. private String hasSsl;
  43. private String callBackUrl;
  44. private String restApiKey;
  45. private String profiles;
  46. private String tokenUrl;
  47. private String userInfoUrl;
  48. private String authorizeUrl;
  49. private String unlinkUrl;
  50. private String protocal;
  51. @PostConstruct
  52. public void init() {
  53. callBackUrl = env.getProperty("kakao.login.callbackUrl");
  54. restApiKey = env.getProperty("kakao.restApiKey");
  55. profiles = env.getProperty("spring.profiles.active").toLowerCase();
  56. tokenUrl = env.getProperty("kakao.tokenUrl");
  57. userInfoUrl = env.getProperty("kakao.userInfoUrl");
  58. authorizeUrl = env.getProperty("kakao.authorizeUrl");
  59. unlinkUrl = env.getProperty("kakao.unlinkUrl");
  60. boolean isSslServer = Boolean.parseBoolean(hasSsl);
  61. if (isSslServer) {
  62. protocal = "https://";
  63. } else {
  64. protocal = "http://";
  65. }
  66. log.debug("\n\n---- Kakao initialization started ----");
  67. log.debug("callBackUrl: [{}]", callBackUrl);
  68. log.debug("restApiKey: [{}]", restApiKey);
  69. log.debug("profiles: [{}]", profiles);
  70. log.debug("tokenUrl: [{}]", tokenUrl);
  71. log.debug("userInfoUrl: [{}]", userInfoUrl);
  72. log.debug("authorizeUrl: [{}]", authorizeUrl);
  73. log.debug("\n--- Kakao initialization completed ----\n");
  74. }
  75. /**
  76. * 카카오 로그인 창
  77. * @param state - 콜백 시 해당 값으로 비교 및 모바일을 redirect 값이 있음
  78. * @return String - 호출 url정보
  79. * @author jsshin
  80. * @since 2021. 02. 05
  81. */
  82. public String getAuthorizeUrl(String state) {
  83. StringBuilder apiUrlBuilder = new StringBuilder();
  84. String redirectUri = GagaFileUtil.getConcatenationPath(protocal + TsfSession.getHttpServletRequest().getServerName(), callBackUrl);
  85. apiUrlBuilder.append(authorizeUrl)
  86. .append("?client_id=")
  87. .append(restApiKey)
  88. .append("&redirect_uri=")
  89. .append(redirectUri)
  90. .append("&response_type=code&state=")
  91. .append(state);
  92. log.info("apiUrlBuilder ===> {}", apiUrlBuilder.toString());
  93. return apiUrlBuilder.toString();
  94. }
  95. /**
  96. * 카카오 전달 받은 코드 값으로 토근값을 받아옴(API)
  97. *
  98. * @param code - 카카오에서 전달 해준 값
  99. * @param state - 콜백 시 해당 값으로 비교 및 모바일을 redirect 값이 있음
  100. * @return GagaMap - 통신으로 받아온 정보
  101. * @author jsshin
  102. * @since 2021. 02. 05
  103. */
  104. public GagaMap getAccessTocken(String code, String state) {
  105. GagaMap resultMap = new GagaMap();
  106. String redirectUri = GagaFileUtil.getConcatenationPath(protocal + TsfSession.getHttpServletRequest().getServerName(), callBackUrl);
  107. String requestGb = "";
  108. try {
  109. MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
  110. params.add("grant_type", "authorization_code");
  111. params.add("client_id", restApiKey);
  112. params.add("redirect_uri", redirectUri);
  113. params.add("code", code);
  114. params.add("state", state);
  115. // state 값에 리다이렉트 url 같이 넘겨줌
  116. if (StringUtils.isNotBlank(state)) {
  117. String[] stateArr = StringUtils.split(state, "!@!");
  118. requestGb = stateArr[1];
  119. }
  120. // Header
  121. HttpHeaders headers = new HttpHeaders();
  122. headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
  123. HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
  124. URI url = URI.create(tokenUrl);
  125. // POST방식으로 호출
  126. ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, request, String.class);
  127. log.info("responseEntity.getStatusCode(): {} ", responseEntity.getStatusCode());
  128. String jsonResult = responseEntity.getBody();
  129. log.info("responseEntity.getBody(): {} ", jsonResult);
  130. Gson gson = new GsonBuilder().create();
  131. resultMap = gson.fromJson(jsonResult, GagaMap.class); //access_token, refresh_token
  132. resultMap.setString("requestGb", requestGb);
  133. } catch (Exception e) {
  134. log.error(e.getMessage());
  135. }
  136. return resultMap;
  137. }
  138. /**
  139. * 카카오 사용자 정보
  140. *
  141. * @param accessToken - 해당 값으로 사용자 정보를 가져옴
  142. * @return GagaMap - 사용자 정보
  143. * @author jsshin
  144. * @since 2021. 02. 05
  145. */
  146. public GagaMap getKakaoUserInfo(String accessToken) {
  147. GagaMap resultMap = new GagaMap();
  148. try {
  149. MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
  150. // Header
  151. HttpHeaders headers = new HttpHeaders();
  152. headers.set("Authorization", "Bearer " + accessToken);
  153. headers.add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
  154. HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
  155. URI url = URI.create(userInfoUrl);
  156. // POST방식으로 호출
  157. ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, request, String.class);
  158. log.info("responseEntity.getStatusCode(): {} ", responseEntity.getStatusCode());
  159. String jsonResult = responseEntity.getBody();
  160. log.info("responseEntity.getBody(): {} ", jsonResult);
  161. Gson gson = new GsonBuilder().create();
  162. JsonObject obj = gson.fromJson(jsonResult, JsonObject.class);
  163. GagaMap properties = gson.fromJson(obj.get("properties"), GagaMap.class);
  164. GagaMap kakaoAccount = gson.fromJson(obj.get("kakao_account"), GagaMap.class);
  165. Locale locale = Locale.KOREA;
  166. String snsId = obj.get("id").toString();
  167. String custNm = EmojiParser.removeAllEmojis(properties.getString("nickname"));
  168. String email = kakaoAccount.getString("email");
  169. String birthYmd = kakaoAccount.getString("birthyear") + kakaoAccount.getString("birthday");
  170. String cellPhnno = getPhoneNumber(kakaoAccount.getString("phone_number"), locale.getCountry());
  171. String sexGb = "";
  172. if (StringUtils.isNotBlank(kakaoAccount.getString("gender"))) {
  173. sexGb = kakaoAccount.getString("gender").equals("male") ? TscConstants.Gender.MALE.value() : TscConstants.Gender.FEMALE.value();
  174. }
  175. String birthSm = "";
  176. if (StringUtils.isNotBlank(kakaoAccount.getString("birthday_type"))) {
  177. birthSm = kakaoAccount.getString("birthday_type").equals("SOLAR") ? "S":"L";
  178. }
  179. String ci = kakaoAccount.getString("ci");
  180. resultMap.setString("snsId", snsId);
  181. resultMap.setString("custNm", custNm);
  182. resultMap.setString("email", email);
  183. resultMap.setString("ci", ci);
  184. resultMap.setString("cellPhnno", cellPhnno);
  185. resultMap.setString("birthYmd", birthYmd);
  186. resultMap.setString("birthSm", birthSm);
  187. resultMap.setString("sexGb", sexGb);
  188. } catch (Exception e) {
  189. log.error(e.getMessage());
  190. }
  191. return resultMap;
  192. }
  193. /**
  194. * 카카오 access_token 새로 발급
  195. *
  196. * @param refreshToken - 해당 값으로 사용자 정보를 가져옴
  197. * @return GagaMap - access_token 값을 준다.
  198. * @author jsshin
  199. * @since 2021. 02. 05
  200. */
  201. public GagaMap getRefreshTocken(String refreshToken) {
  202. GagaMap resultMap = new GagaMap();
  203. try {
  204. MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
  205. params.add("grant_type", "refresh_token");
  206. params.add("client_id", restApiKey);
  207. params.add("refresh_token", refreshToken);
  208. // Header
  209. HttpHeaders headers = new HttpHeaders();
  210. headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
  211. HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
  212. URI url = URI.create(tokenUrl);
  213. // POST방식으로 호출
  214. ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, request, String.class);
  215. log.info("responseEntity.getStatusCode(): {} ", responseEntity.getStatusCode());
  216. String jsonResult = responseEntity.getBody();
  217. log.info("responseEntity.getBody(): {} ", jsonResult);
  218. Gson gson = new GsonBuilder().create();
  219. resultMap = gson.fromJson(jsonResult, GagaMap.class); //access_token
  220. } catch (Exception e) {
  221. log.error(e.getMessage());
  222. }
  223. return resultMap;
  224. }
  225. /**
  226. * 카카오 계정 연동해제
  227. *
  228. * @param accessToken - 토근값
  229. * @return GagaMap - snsId 값이 있으면 연동해제 성공
  230. * @author jsshin
  231. * @since 2021. 02. 05
  232. */
  233. public GagaMap saveUnlink(String accessToken) {
  234. GagaMap resultMap = new GagaMap();
  235. try {
  236. MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
  237. // Header
  238. HttpHeaders headers = new HttpHeaders();
  239. headers.set("Authorization", "Bearer " + accessToken);
  240. headers.add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
  241. HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
  242. URI url = URI.create(unlinkUrl);
  243. // POST방식으로 호출
  244. ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, request, String.class);
  245. log.info("responseEntity.getStatusCode(): {} ", responseEntity.getStatusCode());
  246. String jsonResult = responseEntity.getBody();
  247. log.info("responseEntity.getBody(): {} ", jsonResult);
  248. Gson gson = new GsonBuilder().create();
  249. JsonObject obj = gson.fromJson(jsonResult, JsonObject.class);
  250. resultMap.setString("snsId", obj.get("id").toString());
  251. } catch (Exception e) {
  252. log.error(e.getMessage());
  253. }
  254. return resultMap;
  255. }
  256. /**
  257. * 국가번호 붙여서 넘겨온 전화번호 변호
  258. * +82) 010 1234 5678 -> 010-1234-5678
  259. * @param cellPhnno - 휴대전화번호
  260. * @param country - 국가
  261. * @return String - 010-1234-5678
  262. * @author jsshin
  263. * @since 2021. 02. 05
  264. */
  265. public String getPhoneNumber(String cellPhnno, String country) throws Exception {
  266. String result = "";
  267. if (StringUtils.isNotBlank(cellPhnno)) {
  268. PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
  269. Phonenumber.PhoneNumber numberProto = phoneUtil.parse(cellPhnno, "KR");
  270. result = phoneUtil.format(numberProto, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
  271. }
  272. return result;
  273. }
  274. }