SpringBoot2로 Rest api 만들기(9) – Social Login 연동(kakao)

This commit is contained in:
kimyonghwa
2019-04-18 19:41:37 +09:00
parent 03edf8a653
commit 9fcd390cee
8 changed files with 123 additions and 2 deletions

View File

@@ -29,6 +29,7 @@ dependencies {
implementation 'io.springfox:springfox-swagger2:2.6.1'
implementation 'io.springfox:springfox-swagger-ui:2.6.1'
implementation 'net.rakugakibox.util:yaml-resource-bundle:1.1'
implementation 'com.google.code.gson:gson'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'mysql:mysql-connector-java'

View File

@@ -5,6 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class SpringRestApiApplication {
@@ -16,4 +17,9 @@ public class SpringRestApiApplication {
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}

View File

@@ -31,7 +31,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // jwt token으로 인증할것이므로 세션필요없으므로 생성안함.
.and()
.authorizeRequests() // 다음 리퀘스트에 대한 사용권한 체크
.antMatchers("/*/signin", "/*/signup").permitAll() // 가입 및 인증 주소는 누구나 접근가능
.antMatchers("/*/signin", "/*/signup", "/social/**").permitAll() // 가입 및 인증 주소는 누구나 접근가능
.antMatchers(HttpMethod.GET, "/helloworld/**").permitAll() // hellowworld로 시작하는 GET요청 리소스는 누구나 접근가능
.anyRequest().hasRole("USER") // 그외 나머지 요청은 모두 인증된 회원만 접근 가능
.and()

View File

@@ -0,0 +1,79 @@
package com.rest.api.controller.common;
import com.google.gson.Gson;
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.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;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.ModelAndView;
@RequiredArgsConstructor
@Controller
@RequestMapping("/social/login")
public class SocialController {
private final Environment env;
private final RestTemplate restTemplate;
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;
/**
* 카카오 로그인 페이지
*/
@GetMapping
public ModelAndView socialLogin(ModelAndView mav) {
StringBuilder loginUrl = new StringBuilder()
.append(env.getProperty("spring.social.kakao.url.login"))
.append("?client_id=").append(kakaoClientId)
.append("&response_type=code")
.append("&redirect_uri=").append(baseUrl).append(kakaoRedirect);
mav.addObject("loginUrl", loginUrl);
mav.setViewName("social/login");
return mav;
}
/**
* 카카오 인증 완료 후 리다이렉트 화면
*/
@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.setViewName("social/redirectKakao");
return mav;
}
}

View File

@@ -0,0 +1,14 @@
package com.rest.api.model.social;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class RetKakaoAuth {
private String access_token;
private String token_type;
private String refresh_token;
private long expires_in;
private String scope;
}

View File

@@ -14,4 +14,14 @@ spring:
basename: i18n/exception
encoding: UTF-8
jwt:
secret: govlepel@$&
secret: govlepel@$&
social:
kakao:
client_id: XXXXXXXXXXXXXXXXXXXXXXXX # 앱생성시 받은 REST API 키
redirect: /social/login/kakao
url:
login: https://kauth.kakao.com/oauth/authorize
token: https://kauth.kakao.com/oauth/token
profile: https://kapi.kakao.com/v2/user/me
url:
base: http://localhost:8080

View File

@@ -0,0 +1,6 @@
<button onclick="popupKakaoLogin()">KakaoLogin</button>
<script>
function popupKakaoLogin() {
window.open('${loginUrl}', 'popupKakaoLogin', 'width=300,height=500,scrollbars=0,toolbar=0,menubar=no')
}
</script>

View File

@@ -0,0 +1,5 @@
access_token : ${authInfo.access_token}<br>
token_type : ${authInfo.token_type}<br>
refresh_token : ${authInfo.refresh_token}<br>
expires_in : ${authInfo.expires_in}<br>
scope : ${authInfo.scope}<br>