Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ dependencies {

// AOP
implementation 'org.springframework.boot:spring-boot-starter-aop'

implementation 'org.springframework.boot:spring-boot-starter-webflux'
}

tasks.named('test') {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/sayup/SayUp/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
final String[] PUBLIC_URLS = {
"/api/auth/**", // 인증 관련 API
"/swagger-ui/**", // Swagger UI
"/v3/api-docs/**" // OpenAPI 문서
"/v3/api-docs/**", // OpenAPI 문서
"/callback/**" // 카카오 로그인
};

return http
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/sayup/SayUp/controller/AuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
import com.sayup.SayUp.dto.AuthResponseDTO;
import com.sayup.SayUp.service.AuthService;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
@RequestMapping("/api/auth")
@AllArgsConstructor
public class AuthController {
private final AuthService authService;

public AuthController(AuthService authService) {
this.authService = authService;
}

/**
* 사용자 회원가입 처리
* @param authRequestDTO 사용자 이메일 및 비밀번호 정보
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/sayup/SayUp/entity/User.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.sayup.SayUp.entity;

import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -13,6 +14,9 @@
@Getter
@Setter
public class User {
public User() {
}

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
Expand All @@ -31,6 +35,8 @@ public class User {
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt = LocalDateTime.now();

private String role;

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.sayup.SayUp.kakao.controller;

import com.sayup.SayUp.dto.AuthResponseDTO;
import com.sayup.SayUp.kakao.dto.KakaoUserInfoResponseDto;
import com.sayup.SayUp.kakao.service.KakaoService;
import com.sayup.SayUp.security.JwtTokenProvider;
import com.sayup.SayUp.service.AuthService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
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.bind.annotation.RestController;

import java.io.IOException;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("")
public class KakaoLoginController {

private final KakaoService kakaoService;
private final JwtTokenProvider jwtTokenProvider;
private final AuthService authService;

@GetMapping("/callback")
public ResponseEntity<?> callback(@RequestParam("code") String code) throws IOException {
String accessToken = kakaoService.getAccessTokenFromKakao(code);

KakaoUserInfoResponseDto userInfo = kakaoService.getUserInfo(accessToken);

String email = null;
String jwt = null;
if (userInfo.getKakaoAccount() != null) {
email = userInfo.getKakaoAccount().getEmail();
authService.loadOrCreateUser(email);
jwt = jwtTokenProvider.createTokenFromEmail(email);
}

return ResponseEntity.ok(new AuthResponseDTO(jwt, email));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.sayup.SayUp.kakao.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/login")
public class KakaoLoginPageController {

@Value("${kakao.client_id}")
private String client_id;

@Value("${kakao.redirect_uri}")
private String redirect_uri;

@GetMapping("/page")
public String loginPage(Model model) {
String location = "https://kauth.kakao.com/oauth/authorize?response_type=code&client_id="+client_id+"&redirect_uri="+redirect_uri;
model.addAttribute("location", location);

return "login";
}
}
14 changes: 14 additions & 0 deletions src/main/java/com/sayup/SayUp/kakao/dto/KakaoLoginDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.sayup.SayUp.kakao.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@AllArgsConstructor
@Builder
@Getter
public class KakaoLoginDto {

public String accessToken;
public String refreshToken;
}
27 changes: 27 additions & 0 deletions src/main/java/com/sayup/SayUp/kakao/dto/KakaoTokenResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.sayup.SayUp.kakao.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor //역직렬화를 위한 기본 생성자
@JsonIgnoreProperties(ignoreUnknown = true)
public class KakaoTokenResponseDto {

@JsonProperty("token_type")
public String tokenType;
@JsonProperty("access_token")
public String accessToken;
@JsonProperty("id_token")
public String idToken;
@JsonProperty("expires_in")
public Integer expiresIn;
@JsonProperty("refresh_token")
public String refreshToken;
@JsonProperty("refresh_token_expires_in")
public Integer refreshTokenExpiresIn;
@JsonProperty("scope")
public String scope;
}
190 changes: 190 additions & 0 deletions src/main/java/com/sayup/SayUp/kakao/dto/KakaoUserInfoResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package com.sayup.SayUp.kakao.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.Date;
import java.util.HashMap;

@Getter
@NoArgsConstructor //역직렬화를 위한 기본 생성자
@JsonIgnoreProperties(ignoreUnknown = true)
public class KakaoUserInfoResponseDto {

//회원 번호
@JsonProperty("id")
public Long id;

//자동 연결 설정을 비활성화한 경우만 존재.
//true : 연결 상태, false : 연결 대기 상태
@JsonProperty("has_signed_up")
public Boolean hasSignedUp;

//서비스에 연결 완료된 시각. UTC
@JsonProperty("connected_at")
public Date connectedAt;

//카카오싱크 간편가입을 통해 로그인한 시각. UTC
@JsonProperty("synched_at")
public Date synchedAt;

//사용자 프로퍼티
@JsonProperty("properties")
public HashMap<String, String> properties;

//카카오 계정 정보
@JsonProperty("kakao_account")
public KakaoAccount kakaoAccount;

//uuid 등 추가 정보
@JsonProperty("for_partner")
public Partner partner;

@Getter
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class KakaoAccount {

//프로필 정보 제공 동의 여부
@JsonProperty("profile_needs_agreement")
public Boolean isProfileAgree;

//닉네임 제공 동의 여부
@JsonProperty("profile_nickname_needs_agreement")
public Boolean isNickNameAgree;

//프로필 사진 제공 동의 여부
@JsonProperty("profile_image_needs_agreement")
public Boolean isProfileImageAgree;

//사용자 프로필 정보
@JsonProperty("profile")
public Profile profile;

//이름 제공 동의 여부
@JsonProperty("name_needs_agreement")
public Boolean isNameAgree;

//카카오계정 이름
@JsonProperty("name")
public String name;

//이메일 제공 동의 여부
@JsonProperty("email_needs_agreement")
public Boolean isEmailAgree;

//이메일이 유효 여부
// true : 유효한 이메일, false : 이메일이 다른 카카오 계정에 사용돼 만료
@JsonProperty("is_email_valid")
public Boolean isEmailValid;

//이메일이 인증 여부
//true : 인증된 이메일, false : 인증되지 않은 이메일
@JsonProperty("is_email_verified")
public Boolean isEmailVerified;

//카카오계정 대표 이메일
@JsonProperty("email")
public String email;

//연령대 제공 동의 여부
@JsonProperty("age_range_needs_agreement")
public Boolean isAgeAgree;

//연령대
//참고 https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#req-user-info
@JsonProperty("age_range")
public String ageRange;

//출생 연도 제공 동의 여부
@JsonProperty("birthyear_needs_agreement")
public Boolean isBirthYearAgree;

//출생 연도 (YYYY 형식)
@JsonProperty("birthyear")
public String birthYear;

//생일 제공 동의 여부
@JsonProperty("birthday_needs_agreement")
public Boolean isBirthDayAgree;

//생일 (MMDD 형식)
@JsonProperty("birthday")
public String birthDay;

//생일 타입
// SOLAR(양력) 혹은 LUNAR(음력)
@JsonProperty("birthday_type")
public String birthDayType;

//성별 제공 동의 여부
@JsonProperty("gender_needs_agreement")
public Boolean isGenderAgree;

//성별
@JsonProperty("gender")
public String gender;

//전화번호 제공 동의 여부
@JsonProperty("phone_number_needs_agreement")
public Boolean isPhoneNumberAgree;

//전화번호
//국내 번호인 경우 +82 00-0000-0000 형식
@JsonProperty("phone_number")
public String phoneNumber;

//CI 동의 여부
@JsonProperty("ci_needs_agreement")
public Boolean isCIAgree;

//CI, 연계 정보
@JsonProperty("ci")
public String ci;

//CI 발급 시각, UTC
@JsonProperty("ci_authenticated_at")
public Date ciCreatedAt;

@Getter
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Profile {

//닉네임
@JsonProperty("nickname")
public String nickName;

//프로필 미리보기 이미지 URL
@JsonProperty("thumbnail_image_url")
public String thumbnailImageUrl;

//프로필 사진 URL
@JsonProperty("profile_image_url")
public String profileImageUrl;

//프로필 사진 URL 기본 프로필인지 여부
//true : 기본 프로필, false : 사용자 등록
@JsonProperty("is_default_image")
public String isDefaultImage;

//닉네임이 기본 닉네임인지 여부
//true : 기본 닉네임, false : 사용자 등록
@JsonProperty("is_default_nickname")
public Boolean isDefaultNickName;

}
}

@Getter
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Partner {
//고유 ID
@JsonProperty("uuid")
public String uuid;
}

}
Loading