728x90
반응형
[Springboot] 41. OAuth 2.0 (3단계-Kakao Developers 소셜 로그인 API 토큰 받기)
1. 문서 살펴보기
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
2. 토큰 받아오기
@GetMapping("/kakao")
@ResponseBody // @RestController = @Controller + @ResponseBody
public String getMethodName(@RequestParam(name="code") String code) {
System.out.println("code : "+code);
// POST - 카카오 토큰 요청 받기
// header, body 구성
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", "authorization_code");
params1.add("client_id", "e6c387d854fa01be9131e377baa4686f");
params1.add("redirect_uri", "http://localhost:8080/user/kakao");
params1.add("code", code);
// 헤더+바디 결합
HttpEntity<MultiValueMap<String,String>> reqKakaoMessage
= new HttpEntity<>(params1,header1);
// 통신 요청
ResponseEntity<String> response= rt1.exchange("https://kauth.kakao.com/oauth/token",
HttpMethod.POST, reqKakaoMessage, String.class);
System.out.println("response : "+response);
return response.getBody().toString();
}
3. jsonschema2pojo 사용하기
https://www.jsonschema2pojo.org/
package com.tenco.bank.dto;
import java.util.LinkedHashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"access_token",
"token_type",
"refresh_token",
"expires_in",
"scope",
"refresh_token_expires_in"
})
public class OAuthToken {
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("token_type")
private String tokenType;
@JsonProperty("refresh_token")
private String refreshToken;
@JsonProperty("expires_in")
private Integer expiresIn;
@JsonProperty("scope")
private String scope;
@JsonProperty("refresh_token_expires_in")
private Integer refreshTokenExpiresIn;
@JsonIgnore
private Map<String, Object> additionalProperties = new LinkedHashMap<String, Object>();
@JsonProperty("access_token")
public String getAccessToken() {
return accessToken;
}
@JsonProperty("access_token")
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
@JsonProperty("token_type")
public String getTokenType() {
return tokenType;
}
@JsonProperty("token_type")
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
@JsonProperty("refresh_token")
public String getRefreshToken() {
return refreshToken;
}
@JsonProperty("refresh_token")
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
@JsonProperty("expires_in")
public Integer getExpiresIn() {
return expiresIn;
}
@JsonProperty("expires_in")
public void setExpiresIn(Integer expiresIn) {
this.expiresIn = expiresIn;
}
@JsonProperty("scope")
public String getScope() {
return scope;
}
@JsonProperty("scope")
public void setScope(String scope) {
this.scope = scope;
}
@JsonProperty("refresh_token_expires_in")
public Integer getRefreshTokenExpiresIn() {
return refreshTokenExpiresIn;
}
@JsonProperty("refresh_token_expires_in")
public void setRefreshTokenExpiresIn(Integer refreshTokenExpiresIn) {
this.refreshTokenExpiresIn = refreshTokenExpiresIn;
}
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
4. OAuthToken (Oauth DTO 만들기)
*@JsonNaming
package com.tenco.bank.dto;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Data;
import lombok.ToString;
// JSON 형식에
// 코딩 컨벤션을 스네이크 케이스에서 카멜 노테이션으로 할당하라
@Data
@ToString
@JsonNaming(value = PropertyNamingStrategies.SnakeCaseStrategy.class)
public class OAuthToken {
private String accessToken;
private String tokenType;
private String refreshToken;
private Integer expiresIn;
private String scope;
private Integer refreshTokenExpiresIn;
}
package com.tenco.bank.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import com.tenco.bank.utils.Define;
import com.tenco.bank.dto.OAuthToken;
import com.tenco.bank.dto.SignInDTO;
import com.tenco.bank.dto.SignUpDTO;
import com.tenco.bank.handler.exception.DataDeliveryException;
import com.tenco.bank.repository.model.User;
import com.tenco.bank.service.UserService;
import jakarta.servlet.http.HttpSession;
@Controller // IoC에 대상(싱글톤 패턴으로 관리됨)
@RequestMapping("/user") // 대문 처리
public class UserController {
private UserService userService;
private final HttpSession session;
// DI 처리
@Autowired // 노란색 경고는 사용할 필요 없음 - 가독성 위해서 선언해도 됨
public UserController(UserService service, HttpSession session) {
this.userService = service;
this.session = session;
}
/**
* 회원 가입 페이지 요청
* 주소 설계 : http://localhost:8080/user/sign-up
* @return signUp.jsp
*/
@GetMapping("/sign-up")
public String signUpPage() {
// prefix: /WEB-INF/view/
// return: user/signUp
// suffix: .jsp
return "user/signUp";
}
/**
* 회원 가입 로직 처리 요청
* 주소 설계 : http://localhost:8080/user/sign-up
* @param dto
* @return
*/
@PostMapping("/sign-up")
public String signUpProc(SignUpDTO dto) {
// controller 에서 일반적이 코드 작업
// 1. 인증검사 (여기서는 인증검사 불 필요)
// 2. 유효성 검사
if(dto.getUsername() == null || dto.getUsername().isEmpty()) {
throw new DataDeliveryException(Define.ENTER_YOUR_USERNAME, HttpStatus.BAD_REQUEST);
}
if(dto.getPassword() == null || dto.getPassword().isEmpty()) {
throw new DataDeliveryException(Define.ENTER_YOUR_PASSWORD, HttpStatus.BAD_REQUEST);
}
if(dto.getFullname() == null || dto.getFullname().isEmpty()) {
throw new DataDeliveryException(Define.ENTER_YOUR_FULLNAME, HttpStatus.BAD_REQUEST);
}
userService.createUser(dto);
return "redirect:/user/sign-in";
}
/*
* 로그인 화면 요청
* 주소설계 : http://localhost:8080/user/sign-in
*/
@GetMapping("/sign-in")
public String singInPage() {
// 인증검사 x
// 유효성검사 x
return "user/signIn";
}
/**
* 로그인 요청 처리
* 주소설계 : http://localhost:8080/user/sign-in
* @return
*/
@PostMapping("/sign-in")
public String signProc(SignInDTO dto) {
// 1. 인증 검사 x
// 2. 유효성 검사
if(dto.getUsername() == null || dto.getUsername().isEmpty()) {
throw new DataDeliveryException(Define.ENTER_YOUR_USERNAME, HttpStatus.BAD_REQUEST);
}
if(dto.getPassword() == null || dto.getPassword().isEmpty()) {
throw new DataDeliveryException(Define.ENTER_YOUR_PASSWORD, HttpStatus.BAD_REQUEST);
}
// 서비스 호출
User principal = userService.readUser(dto);
// 세션 메모리에 등록 처리
session.setAttribute(Define.PRINCIPAL, principal);
// 새로운 페이지로 이동 처리
// TODO - 계좌 목록 페이지 이동처리 예정
return "redirect:/index";
}
// 코드 추가
@GetMapping("/logout")
public String logout() {
session.invalidate(); // 로그아웃 됨
return "redirect:/user/sign-in";
}
@GetMapping("/kakao")
@ResponseBody // @RestController = @Controller + @ResponseBody
public String getMethodName(@RequestParam(name="code") String code) {
System.out.println("code : "+code);
// POST - 카카오 토큰 요청 받기
// header, body 구성
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", "authorization_code");
params1.add("client_id", "e6c387d854fa01be9131e377baa4686f");
params1.add("redirect_uri", "http://localhost:8080/user/kakao");
params1.add("code", code);
// 헤더+바디 결합
HttpEntity<MultiValueMap<String,String>> reqKakaoMessage
= new HttpEntity<>(params1,header1);
// 통신 요청
ResponseEntity<OAuthToken> response= rt1.exchange("https://kauth.kakao.com/oauth/token",
HttpMethod.POST, reqKakaoMessage, OAuthToken.class);
System.out.println("response : "+response.getBody().toString());
return response.getBody().toString();
}
}
728x90
반응형
'Springboot' 카테고리의 다른 글
[Springboot] 43. OAuth 2.0 (5단계-소셜 로그인 API 연동- 자동 회원가입/로그인 처리) (1) | 2024.08.16 |
---|---|
[Springboot] 42. OAuth 2.0 (4단계-Kakao Developers 소셜 로그인 사용자 정보 받아오기) (0) | 2024.08.16 |
[Springboot] 40. OAuth 2.0 (2단계-Kakao Developers API 응답 코드 받기) (0) | 2024.08.14 |
[Springboot] 39. OAuth 2.0 (1단계-Kakao Developers 사용하기) (0) | 2024.08.14 |
[Springboot] 38. Server to Server란? (0) | 2024.08.14 |