diff --git a/build.gradle b/build.gradle index 4a5f036..c11d202 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ dependencies { implementation 'io.jsonwebtoken:jjwt:0.9.1' implementation group: 'javax.persistence', name: 'persistence-api', version: '1.0.2' implementation group: 'com.querydsl', name: 'querydsl-jpa', version: '5.0.0' - + implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1' implementation 'mysql:mysql-connector-java:8.0.32' testImplementation 'junit:junit:4.13.1' testImplementation 'org.projectlombok:lombok:1.18.26' diff --git a/src/main/java/mvc/promiseme/config/AppConfig.java b/src/main/java/mvc/promiseme/config/AppConfig.java index a28450f..90a1c60 100644 --- a/src/main/java/mvc/promiseme/config/AppConfig.java +++ b/src/main/java/mvc/promiseme/config/AppConfig.java @@ -2,6 +2,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory; +import mvc.promiseme.kakao.KakaoApi; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -16,5 +17,11 @@ public class AppConfig { @Bean public JPAQueryFactory queryFactory(){ return new JPAQueryFactory(entityManager); + + + } + @Bean + public KakaoApi kakaoApi() { + return new KakaoApi(); } } \ No newline at end of file diff --git a/src/main/java/mvc/promiseme/kakao/KakaoApi.java b/src/main/java/mvc/promiseme/kakao/KakaoApi.java new file mode 100644 index 0000000..62237bd --- /dev/null +++ b/src/main/java/mvc/promiseme/kakao/KakaoApi.java @@ -0,0 +1,75 @@ +package mvc.promiseme.kakao; + +import lombok.Data; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +@Data +public class KakaoApi { + // class KakaoApi + @Value("${KAKAO_API_KEY}") + private String kakaoApiKey; + + @Value("${KAKAO_REDIRECT_URI}") + private String kakaoRedirectUri; + + public String getKakaoAccessToken(String code) throws ParseException { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("grant_type", "authorization_code"); + params.add("client_id", kakaoApiKey); + params.add("redirect_uri", kakaoRedirectUri); + params.add("code", code); + + // http 헤더 고정 + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); + + //http 헤더와 바디 합치기 + HttpEntity> entity = new HttpEntity<>(params, headers); + + //http post 요청 보내기 + RestTemplate rt = new RestTemplate(); + ResponseEntity response = rt.exchange( + "https://kauth.kakao.com/oauth/token", //{요청할 서버 주소} + HttpMethod.POST, //{요청할 방식} + entity, // {요청할 때 보낼 데이터} + String.class + ); + + String responseBody = response.getBody(); + JSONParser parser = new JSONParser(); + JSONObject object = (JSONObject) parser.parse(responseBody); + String accessToken = (String) object.get("access_token"); + return accessToken; + } + + public ResponseEntity getUserInfo(String accessToken) { + + // http 헤더 + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); + headers.add("Authorization", "Bearer "+accessToken); + + //http 헤더와 바디 합치기 + HttpEntity> entity = new HttpEntity<>(headers); + + //http post 요청 보내기 + RestTemplate rt = new RestTemplate(); + ResponseEntity response = rt.exchange( + "https://kapi.kakao.com/v2/user/me", //{요청할 서버 주소} + HttpMethod.POST, //{요청할 방식} + entity, // {요청할 때 보낼 데이터} + String.class + ); + return response; + } +} \ No newline at end of file diff --git a/src/main/java/mvc/promiseme/users/controller/UserController.java b/src/main/java/mvc/promiseme/users/controller/UserController.java index f6cf9b8..f1a00b3 100644 --- a/src/main/java/mvc/promiseme/users/controller/UserController.java +++ b/src/main/java/mvc/promiseme/users/controller/UserController.java @@ -11,16 +11,17 @@ import lombok.extern.slf4j.Slf4j; import mvc.promiseme.common.exception.ErrorCode; import mvc.promiseme.common.exception.ErrorResponse; +import mvc.promiseme.kakao.KakaoApi; import mvc.promiseme.project.dto.ProjectResponseDTO; import mvc.promiseme.users.dto.LoginRequestDTO; import mvc.promiseme.users.dto.LoginResponseDTO; import mvc.promiseme.users.dto.UserDTO; import mvc.promiseme.users.service.UserService; +import org.json.simple.parser.ParseException; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.Map; @Slf4j @@ -29,6 +30,7 @@ @RequiredArgsConstructor public class UserController { private final UserService userService; + private final KakaoApi kakaoApi; @Operation(summary = "회원가입", description = "닉네임과 이메일, 패스워드를 입력받아 회원가입을 진행한다.") @ApiResponses({ @@ -56,6 +58,30 @@ public class UserController { return ResponseEntity.ok(userService.login(loginRequestDTO)); } + + + + @Operation(summary = "카카오로그인", description = "카카오 로그인 창으로 이동 ") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "성공", content = @Content(schema = @Schema(implementation = Map.class))), + }) + @GetMapping("user/loginKakao") + public ResponseEntity> kakaoLogin(){ + Map map = new HashMap<>(); + map.put("kakaoApiKey", kakaoApi.getKakaoApiKey()); + map.put("redirectUri", kakaoApi.getKakaoRedirectUri()); + return ResponseEntity.ok(map); + } + + @GetMapping("/login/oauth/kakao") + @ResponseBody + public String kakaoCallback(String code) throws ParseException { + String accessToken = kakaoApi.getKakaoAccessToken(code); + ResponseEntity userInfo = kakaoApi.getUserInfo(accessToken); + return "카카오 인증완료 반환값: " + userInfo; + } + + @Operation(summary = "로그아웃", description = "로그아웃을 진행한다.") @PostMapping("/users/logout") public ResponseEntitylogout(@RequestBody String token){