Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
52ced5f
🚀chore: build.gradle 의존성 추가(OAuth2)
chw1230 May 22, 2025
95aee85
🚀chore: application.yml 추가(OAuth2)
chw1230 May 22, 2025
c5bd729
🚀chore: 불필요한 어노테이션 제거
chw1230 May 22, 2025
05e20f2
💄style: 오탈자 수정
chw1230 May 22, 2025
3617f37
💄style: 오탈자 수정
chw1230 May 22, 2025
460e807
💄style: 오탈자 수정
chw1230 May 22, 2025
996d42a
💄style: 오탈자 수정
chw1230 May 22, 2025
240c68e
♻️refactor: REDIRECT_URL 설정
chw1230 May 22, 2025
e5bb4cb
✨feat: KakaoUserInfoResponseDTO 추가
chw1230 May 22, 2025
88cae38
✨feat: KakaoTokenResponseDTO 추가
chw1230 May 22, 2025
e14b66b
✨feat: KakaoService 추가
chw1230 May 22, 2025
9db0fa6
💄style: 오탈자 수정
chw1230 May 23, 2025
eb9b68f
💄style: 오탈자 수정
chw1230 May 23, 2025
2930507
✨feat: 카카오 소셜로그인 구현
chw1230 May 23, 2025
82cb3af
✨feat: 카카오 소셜로그인 구현
chw1230 May 26, 2025
abccbbe
🚀chore: build.gradle 의존성 추가(Redis)
chw1230 May 26, 2025
ea43eeb
🚀chore: build.gradle 의존성 추가(Redis)
chw1230 May 26, 2025
9661b86
🚀chore: Redis port 설정 변경
chw1230 May 27, 2025
9207765
✨feat: Redis 로그인 Refresh Token 관리 추가
chw1230 May 27, 2025
558c572
🚀chore: 패키지 위치 변경
chw1230 May 27, 2025
bcf1578
✨feat: SMTP 구현
chw1230 May 27, 2025
caad9d8
✨feat: SMTP 구현
chw1230 May 28, 2025
3694a7b
✨feat: SMTP 구현
chw1230 May 28, 2025
1a6610a
✨feat: SMTP 구현, @value를 통해서 환경 변수 설정 가져오기
chw1230 May 28, 2025
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
9 changes: 9 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ dependencies {

// Security
implementation 'org.springframework.boot:spring-boot-starter-security'

//Webflux
implementation 'org.springframework.boot:spring-boot-starter-webflux'

// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// SMTP
implementation 'org.springframework.boot:spring-boot-starter-mail'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

@EnableJpaAuditing
@SpringBootApplication
//@EntityScan(basePackages = "com.project.likelion13thbe")
public class LikeLion13thBeApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package com.project.likelion13thbe.domain.member.controller;

import com.project.likelion13thbe.domain.member.dto.request.MemberRequestDTO;
import com.project.likelion13thbe.domain.member.dto.response.KakaoUserInfoResponseDTO;
import com.project.likelion13thbe.domain.member.dto.response.MemberResponseDTO;
import com.project.likelion13thbe.domain.member.entity.Member;
import com.project.likelion13thbe.domain.member.repository.MemberRepository;
import com.project.likelion13thbe.domain.member.service.KakaoService;
import com.project.likelion13thbe.domain.member.service.command.MemberCommandService;
import com.project.likelion13thbe.domain.member.service.query.MemberQueryService;
import com.project.likelion13thbe.global.Security.AuthErrorCode;
import com.project.likelion13thbe.global.Security.AuthException;
import com.project.likelion13thbe.global.Security.DTO.JwtDTO;
import com.project.likelion13thbe.global.Security.AuthService;
import com.project.likelion13thbe.global.Security.DTO.JwtDto;
import com.project.likelion13thbe.global.apiPayload.CustomResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
Expand All @@ -20,6 +25,8 @@
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
import java.util.UUID;

@RestController
@RequiredArgsConstructor
Expand All @@ -29,27 +36,44 @@ public class MemberController {

private final MemberCommandService memberCommandService;
private final MemberQueryService memberQueryService;
private final KakaoService kakaoService;
private final AuthService authService;
private final MemberRepository memberRepository;

@Operation(summary = "카카오 로그인", description = "카카오 로그인을 수행합니다.")
@Operation(summary = "카카오 로그인", description = "카카오 로그인을 수행")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "카카오 로그인 성공")
})
@PostMapping("/login/kakao")
public ResponseEntity<Void> kakaoLogin() {
// 로그인 로직
return ResponseEntity.ok().build();
@GetMapping("/callback/kakao")
public CustomResponse<JwtDto> callbackKakaoLogin(@RequestParam("code") String code){
// 1. 카카오 인증서버에서 토큰을 발급받는다.
// 인가code와 Redirect URL을 파라미터로 전달하여 카카오 인증서버에 요청.
// String accessToken = kakaoService.getAccessTokenFromKakao(code);

// 2. 1번에서 받은 토큰으로 카카오 리소스 서버에 사용자의 정보 요청.
// KakaoUserInfoResponseDTO userInfo = kakaoService.getUserInfo(accessToken);

// 3. 회원가입 & 로그인 처리
// 여기에 서버 사용자 로그인(인증) 또는 회원가입 로직 추가
// 이메일이 있으면 로그인 없으면 회원가입 시키기

// 서비스로 넘겨서 처리하기
JwtDto jwtDto = kakaoService.handleKakaoLogin(code);
return CustomResponse.onSuccess(jwtDto);
}

@Operation(summary = "일반 로그인")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = JwtDTO.class))) })
schema = @Schema(implementation = JwtDto.class))) })
@PostMapping("/login")
public ResponseEntity<JwtDTO> localLogin(@RequestBody MemberRequestDTO.LoginRequestDTO loginRequestDTO) {
return null;
public ResponseEntity<JwtDto> localLogin(@RequestBody MemberRequestDTO.LoginRequestDTO loginRequestDTO) {
JwtDto jwtDto = authService.login(loginRequestDTO);
return ResponseEntity.ok(jwtDto);
}


@Operation(summary = "비밀번호 수정", description = "비밀번호를 수정")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "비밀번호 수정 성공")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public static class MemberReqDTO {
private String note;
}
// 사용자 회원가입
@Builder
public record MemberCreateRequestDTO (
String email,
String name,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.project.likelion13thbe.domain.member.dto.response;

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;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package com.project.likelion13thbe.domain.member.dto.response;


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 static 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 static 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 static class Partner {
//고유 ID
@JsonProperty("uuid")
public String uuid;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ public interface MemberRepository extends JpaRepository<Member, Long> {
// 소프트 delete
@Query("SELECT m FROM Member m WHERE m.id = :id AND m.deletedAt IS null ")
Optional<Member> findByIdNotDeleted(@Param("id") Long id);


Optional<Member> findByEmail(String email);
}
Loading