SpringBoot2로 Rest api 만들기(10) – Social Login 연동(kakao)
- UserService name change : KakaoService - Social signin, signup Test
This commit is contained in:
@@ -1,14 +1,11 @@
|
||||
package com.rest.api.controller.common;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.rest.api.model.social.RetKakaoAuth;
|
||||
import com.rest.api.service.social.KakaoService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -21,10 +18,9 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
public class SocialController {
|
||||
|
||||
private final Environment env;
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private final Gson gson;
|
||||
private final KakaoService kakaoService;
|
||||
|
||||
@Value("${spring.url.base}")
|
||||
private String baseUrl;
|
||||
@@ -57,22 +53,7 @@ public class SocialController {
|
||||
*/
|
||||
@GetMapping(value = "/kakao")
|
||||
public ModelAndView redirectKakao(ModelAndView mav, @RequestParam String code) {
|
||||
// Set header : Content-type: application/x-www-form-urlencoded
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
// Set parameter
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("grant_type", "authorization_code");
|
||||
params.add("client_id", kakaoClientId);
|
||||
params.add("redirect_uri", baseUrl + kakaoRedirect);
|
||||
params.add("code", code);
|
||||
// Set http entity
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
|
||||
ResponseEntity<String> response = restTemplate.postForEntity(env.getProperty("spring.social.kakao.url.token"), request, String.class);
|
||||
if (response.getStatusCode() == HttpStatus.OK) {
|
||||
RetKakaoAuth authInfo = gson.fromJson(response.getBody(), RetKakaoAuth.class);
|
||||
mav.addObject("authInfo", authInfo);
|
||||
}
|
||||
mav.addObject("authInfo", kakaoService.getKakaoTokenInfo(code));
|
||||
mav.setViewName("social/redirectKakao");
|
||||
return mav;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.rest.api.controller.v1;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.rest.api.advice.exception.CEmailSigninFailedException;
|
||||
import com.rest.api.advice.exception.CUserExistException;
|
||||
import com.rest.api.advice.exception.CUserNotFoundException;
|
||||
@@ -11,15 +10,13 @@ import com.rest.api.model.response.SingleResult;
|
||||
import com.rest.api.model.social.KakaoProfile;
|
||||
import com.rest.api.repo.UserJpaRepo;
|
||||
import com.rest.api.service.ResponseService;
|
||||
import com.rest.api.service.user.UserService;
|
||||
import com.rest.api.service.social.KakaoService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
@@ -34,10 +31,7 @@ public class SignController {
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
private final ResponseService responseService;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final RestTemplate restTemplate;
|
||||
private final Environment env;
|
||||
private final Gson gson;
|
||||
private final UserService userService;
|
||||
private final KakaoService kakaoService;
|
||||
|
||||
@ApiOperation(value = "로그인", notes = "이메일 회원 로그인을 한다.")
|
||||
@PostMapping(value = "/signin")
|
||||
@@ -57,7 +51,7 @@ public class SignController {
|
||||
@ApiParam(value = "서비스 제공자 provider", required = true, defaultValue = "kakao") @PathVariable String provider,
|
||||
@ApiParam(value = "소셜 access_token", required = true) @RequestParam String accessToken) {
|
||||
|
||||
KakaoProfile profile = userService.getKakaoProfile(accessToken);
|
||||
KakaoProfile profile = kakaoService.getKakaoProfile(accessToken);
|
||||
User user = userJpaRepo.findByUidAndProvider(String.valueOf(profile.getId()), provider).orElseThrow(CUserNotFoundException::new);
|
||||
return responseService.getSingleResult(jwtTokenProvider.createToken(String.valueOf(user.getMsrl()), user.getRoles()));
|
||||
}
|
||||
@@ -83,7 +77,7 @@ public class SignController {
|
||||
@ApiParam(value = "소셜 access_token", required = true) @RequestParam String accessToken,
|
||||
@ApiParam(value = "이름", required = true) @RequestParam String name) {
|
||||
|
||||
KakaoProfile profile = userService.getKakaoProfile(accessToken);
|
||||
KakaoProfile profile = kakaoService.getKakaoProfile(accessToken);
|
||||
Optional<User> user = userJpaRepo.findByUidAndProvider(String.valueOf(profile.getId()), provider);
|
||||
if (user.isPresent())
|
||||
throw new CUserExistException();
|
||||
|
||||
@@ -2,15 +2,18 @@ package com.rest.api.model.social;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class KakaoProfile {
|
||||
private Long id;
|
||||
private Properties properties;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
private static class Properties {
|
||||
private String nickname;
|
||||
private String thumbnail_image;
|
||||
|
||||
70
src/main/java/com/rest/api/service/social/KakaoService.java
Normal file
70
src/main/java/com/rest/api/service/social/KakaoService.java
Normal file
@@ -0,0 +1,70 @@
|
||||
package com.rest.api.service.social;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.rest.api.advice.exception.CCommunicationException;
|
||||
import com.rest.api.model.social.KakaoProfile;
|
||||
import com.rest.api.model.social.RetKakaoAuth;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class KakaoService {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
private final Environment env;
|
||||
private final Gson gson;
|
||||
|
||||
@Value("${spring.url.base}")
|
||||
private String baseUrl;
|
||||
|
||||
@Value("${spring.social.kakao.client_id}")
|
||||
private String kakaoClientId;
|
||||
|
||||
@Value("${spring.social.kakao.redirect}")
|
||||
private String kakaoRedirect;
|
||||
|
||||
public KakaoProfile getKakaoProfile(String accessToken) {
|
||||
// Set header : Content-type: application/x-www-form-urlencoded
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("Authorization", "Bearer " + accessToken);
|
||||
|
||||
// Set http entity
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(null, headers);
|
||||
try {
|
||||
// Request profile
|
||||
ResponseEntity<String> response = restTemplate.postForEntity(env.getProperty("spring.social.kakao.url.profile"), request, String.class);
|
||||
if (response.getStatusCode() == HttpStatus.OK)
|
||||
return gson.fromJson(response.getBody(), KakaoProfile.class);
|
||||
} catch (Exception e) {
|
||||
throw new CCommunicationException();
|
||||
}
|
||||
throw new CCommunicationException();
|
||||
}
|
||||
|
||||
public RetKakaoAuth getKakaoTokenInfo(String code) {
|
||||
// Set header : Content-type: application/x-www-form-urlencoded
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
// Set parameter
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("grant_type", "authorization_code");
|
||||
params.add("client_id", kakaoClientId);
|
||||
params.add("redirect_uri", baseUrl + kakaoRedirect);
|
||||
params.add("code", code);
|
||||
// Set http entity
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
|
||||
ResponseEntity<String> response = restTemplate.postForEntity(env.getProperty("spring.social.kakao.url.token"), request, String.class);
|
||||
if (response.getStatusCode() == HttpStatus.OK) {
|
||||
return gson.fromJson(response.getBody(), RetKakaoAuth.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.rest.api.service.user;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.rest.api.advice.exception.CCommunicationException;
|
||||
import com.rest.api.model.social.KakaoProfile;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
private final Environment env;
|
||||
private final Gson gson;
|
||||
|
||||
public KakaoProfile getKakaoProfile(String accessToken) {
|
||||
// Set header : Content-type: application/x-www-form-urlencoded
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.set("Authorization", "Bearer " + accessToken);
|
||||
|
||||
// Set http entity
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(null, headers);
|
||||
ResponseEntity<String> response = restTemplate.postForEntity(env.getProperty("spring.social.kakao.url.profile"), request, String.class);
|
||||
if (response.getStatusCode() == HttpStatus.OK)
|
||||
return gson.fromJson(response.getBody(), KakaoProfile.class);
|
||||
else
|
||||
throw new CCommunicationException();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<button onclick="popupKakaoLogin()">KakaoLogin</button>
|
||||
<script>
|
||||
function popupKakaoLogin() {
|
||||
window.open('${loginUrl}', 'popupKakaoLogin', 'width=300,height=500,scrollbars=0,toolbar=0,menubar=no')
|
||||
window.open('${loginUrl}', 'popupKakaoLogin', 'width=700,height=500,scrollbars=0,toolbar=0,menubar=no')
|
||||
}
|
||||
</script>
|
||||
@@ -1,19 +1,16 @@
|
||||
package com.rest.api.controller.v1;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
@@ -86,4 +83,39 @@ public class SignControllerTest {
|
||||
.andExpect(jsonPath("$.success").value(false))
|
||||
.andExpect(jsonPath("$.code").value(-9999));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signInProviderFail() throws Exception {
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("accessToken", "XXXXXXXX");
|
||||
mockMvc.perform(post("/v1/signin/kakao").params(params))
|
||||
.andDo(print())
|
||||
.andExpect(status().is5xxServerError())
|
||||
.andExpect(jsonPath("$.success").value(false))
|
||||
.andExpect(jsonPath("$.code").value(-1004));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signUpProvider() throws Exception {
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("accessToken", "HizF3ir9522bMW3shkO0x0T9zBdXFCW1WsF56Qo9dVsAAAFqMwTqHw");
|
||||
params.add("name", "kakaoKing!");
|
||||
mockMvc.perform(post("/v1/signup/kakao").params(params))
|
||||
.andDo(print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
.andExpect(jsonPath("$.code").value(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signInProvider() throws Exception {
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("accessToken", "HizF3ir9522bMW3shkO0x0T9zBdXFCW1WsF56Qo9dVsAAAFqMwTqHw");
|
||||
mockMvc.perform(post("/v1/signin/kakao").params(params))
|
||||
.andDo(print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data").exists());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.rest.api.service.social;
|
||||
|
||||
import com.rest.api.model.social.KakaoProfile;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class KakaoServiceTest {
|
||||
|
||||
@Autowired
|
||||
private KakaoService kakaoService;
|
||||
|
||||
@Test
|
||||
public void whenGetKakaoProfile_thenReturnProfile() {
|
||||
|
||||
String accessToken = "xjsMzpQtIr4w13FIQvL3R7BW7X4yvm1KmzXCTwopyWAAAAFqMxEcwA";
|
||||
// given
|
||||
KakaoProfile profile = kakaoService.getKakaoProfile(accessToken);
|
||||
// then
|
||||
assertNotNull(profile);
|
||||
assertEquals(profile.getId(), Long.valueOf(1066788171));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user