diff --git a/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java b/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java index 78123a93..27cfc401 100644 --- a/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java +++ b/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java @@ -17,10 +17,11 @@ public enum MemberBusinessCode implements BusinessCode { SUCCESS_VALIDATE_PASSWORD_MEMBER(HttpStatus.OK.value(), "BMC008", "비밀번호가 확인 되었습니다."), SUCCESS_REQUEST_UPDATE_WASH_INFO_MEMBER(HttpStatus.OK.value(), "BMC009", "WashInfo 정보가 변경 되었습니다."), SUCCESS_REQUEST_UPDATE_CAR_INFO_MEMBER(HttpStatus.OK.value(), "BMC010", "CarInfo 정보가 변경 되었습니다."), - SUCCESS_REQUEST_FIND_MEMBER_ID(HttpStatus.OK.value(), "BMC011", "회원 아이디 찾기 메일이 발송되었습니다."), + SUCCESS_REQUEST_FIND_MEMBER_ID(HttpStatus.OK.value(), "BMC011","회원 아이디 찾기 메일이 발송되었습니다."), SUCCESS_REQUEST_SEND_RESET_PASSWORD_EMAIL(HttpStatus.OK.value(), "BMC012", "회원 비밀번호 초기화 메일이 발송되었습니다."), SUCCESS_REQUEST_RESET_PASSWORD_PAGE(HttpStatus.FOUND.value(), "BMC013", "비밀번호 초기화 토큰이 유효하므로 비밀번호 초기화 페이지로 접근합니다."), - SUCCESS_REQUEST_RESET_PASSWORD(HttpStatus.OK.value(), "BMC013", "비밀번호가 초기화되었습니다."); + SUCCESS_REQUEST_RESET_PASSWORD(HttpStatus.OK.value(), "BMC014", "비밀번호가 초기화되었습니다."), + SUCCESS_REQUEST_LOGIN_MEMBER_KAKAO(HttpStatus.OK.value(), "BMC015", "로그인 성공"); private final int status; private final String code; diff --git a/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java b/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java index 4e32e1a2..ccc35921 100644 --- a/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java +++ b/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java @@ -14,8 +14,8 @@ public enum MemberErrorCode implements ErrorCode { FAILED_GENERATE_LOGIN_REQUEST_INFO(HttpStatus.INTERNAL_SERVER_ERROR.value(), "EMC005", "정보 불일치로 인한 로그인 정보 생성 실패"), FAILED_REQUEST_LOGIN(HttpStatus.BAD_REQUEST.value(), "EMC006", "정보 불일치로 인한 로그인 실패"), FAILED_FIND_MEMBER_INFO(HttpStatus.BAD_REQUEST.value(), "EMC007", "요청 회원정보가 존재하지 않습니다."), - EXPIRED_PASSWORD_RESET_TOKEN(HttpStatus.NOT_FOUND.value(), "EMC008", "유효하지 않은 비밀번호 초기화 토큰입니다"); - + EXPIRED_PASSWORD_RESET_TOKEN(HttpStatus.NOT_FOUND.value(), "EMC008", "유효하지 않은 비밀번호 초기화 토큰입니다"), + FAILED_REQUEST_LOGIN_FOR_KAKAO(HttpStatus.BAD_REQUEST.value(), "EMC009", "카카오 로그인 정보를 찾을 수 없습니다."); private final int status; private final String code; diff --git a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java index 6bc58736..8057428a 100644 --- a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java +++ b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java @@ -1,6 +1,7 @@ package com.kernel360.member.controller; +import com.fasterxml.jackson.core.JsonProcessingException; import com.kernel360.carinfo.entity.CarInfo; import com.kernel360.member.code.MemberBusinessCode; import com.kernel360.member.dto.CarInfoDto; @@ -108,4 +109,12 @@ public ResponseEntity> resetPassword(@RequestBody MemberCred return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_RESET_PASSWORD); } + + @GetMapping("/login/forKakao") + public ResponseEntity> loginForKakao(@RequestHeader("Authorization") String accessToken) { + + MemberDto member = memberService.loginForKakao(accessToken); + + return ApiResponse.toResponseEntity(SUCCESS_REQUEST_LOGIN_MEMBER, member); + } } diff --git a/module-api/src/main/java/com/kernel360/member/dto/KakaoUserDto.java b/module-api/src/main/java/com/kernel360/member/dto/KakaoUserDto.java new file mode 100644 index 00000000..c9c76c33 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/member/dto/KakaoUserDto.java @@ -0,0 +1,16 @@ +package com.kernel360.member.dto; + +public record KakaoUserDto( + String id, + String email +) { + public static KakaoUserDto of( + String id, + String email + ){ + return new KakaoUserDto( + id, + email + ); + } +} diff --git a/module-api/src/main/java/com/kernel360/member/dto/MemberDto.java b/module-api/src/main/java/com/kernel360/member/dto/MemberDto.java index a580385f..7f7bee9e 100644 --- a/module-api/src/main/java/com/kernel360/member/dto/MemberDto.java +++ b/module-api/src/main/java/com/kernel360/member/dto/MemberDto.java @@ -66,6 +66,22 @@ public static MemberDto from(Member entity) { ); } + public static MemberDto fromKakao(MemberDto dto, String token) { + return MemberDto.of( + dto.memberNo(), + dto.id(), + dto.email(), + dto.password(), + dto.gender(), + dto.age(), + dto.createdAt(), + dto.createdBy(), + dto.modifiedAt(), + dto.modifiedBy(), + token + ); + } + public Member toEntity() { return Member.of( this.memberNo(), diff --git a/module-api/src/main/java/com/kernel360/member/enumset/Age.java b/module-api/src/main/java/com/kernel360/member/enumset/Age.java index d1af5a2d..239bddc1 100644 --- a/module-api/src/main/java/com/kernel360/member/enumset/Age.java +++ b/module-api/src/main/java/com/kernel360/member/enumset/Age.java @@ -10,7 +10,8 @@ public enum Age { AGE_30(30), AGE_40(40), AGE_50(50), - AGE_60(60); + AGE_60(60), + AGE_99(99); private final int value; diff --git a/module-api/src/main/java/com/kernel360/member/enumset/Gender.java b/module-api/src/main/java/com/kernel360/member/enumset/Gender.java index 0988155f..9ae46a1d 100644 --- a/module-api/src/main/java/com/kernel360/member/enumset/Gender.java +++ b/module-api/src/main/java/com/kernel360/member/enumset/Gender.java @@ -6,8 +6,9 @@ @RequiredArgsConstructor public enum Gender { - man(0), - woman(1); + MALE(0), + FEMALE(1), + OTHERS(99); private final int value; public static String ordinalToName(int value) { diff --git a/module-api/src/main/java/com/kernel360/member/service/KakaoRequest.java b/module-api/src/main/java/com/kernel360/member/service/KakaoRequest.java new file mode 100644 index 00000000..15164ff7 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/member/service/KakaoRequest.java @@ -0,0 +1,47 @@ +package com.kernel360.member.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.kernel360.exception.BusinessException; +import com.kernel360.member.code.MemberErrorCode; +import com.kernel360.member.dto.KakaoUserDto; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class KakaoRequest { + + public KakaoUserDto getKakaoUserByToken(String accessToken) { + + String url = "https://kapi.kakao.com/v2/user/me"; + + HttpHeaders headers = new HttpHeaders(); + + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + headers.set("Authorization", "Bearer "+accessToken); + headers.set("charset", "utf-8"); + + HttpEntity requestEntity = new HttpEntity<>(headers); + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class); + + ObjectMapper mapper = new ObjectMapper(); + Map kakaoResponse; + + try { + kakaoResponse = mapper.readValue(responseEntity.getBody(), HashMap.class); + }catch (Exception e){ + throw new BusinessException(MemberErrorCode.FAILED_REQUEST_LOGIN_FOR_KAKAO); + } + Map kakaoAccount = mapper.convertValue(kakaoResponse.get("kakao_account"), HashMap.class); + + KakaoUserDto dto = KakaoUserDto.of(kakaoResponse.get("id").toString(),kakaoAccount.get("email").toString()); + + return dto; + } + + +} diff --git a/module-api/src/main/java/com/kernel360/member/service/MemberService.java b/module-api/src/main/java/com/kernel360/member/service/MemberService.java index 0065d696..4b46f250 100644 --- a/module-api/src/main/java/com/kernel360/member/service/MemberService.java +++ b/module-api/src/main/java/com/kernel360/member/service/MemberService.java @@ -6,10 +6,7 @@ import com.kernel360.commoncode.service.CommonCodeService; import com.kernel360.exception.BusinessException; import com.kernel360.member.code.MemberErrorCode; -import com.kernel360.member.dto.CarInfoDto; -import com.kernel360.member.dto.MemberDto; -import com.kernel360.member.dto.MemberInfo; -import com.kernel360.member.dto.WashInfoDto; +import com.kernel360.member.dto.*; import com.kernel360.member.entity.Member; import com.kernel360.member.enumset.Age; import com.kernel360.member.enumset.Gender; @@ -39,6 +36,7 @@ public class MemberService { private final CommonCodeService commonCodeService; private final CarInfoRepository carInfoRepository; private final WashInfoRepository washInfoRepository; + private final KakaoRequest kakaoRequest; @Transactional public void joinMember(MemberDto requestDto) { @@ -191,6 +189,7 @@ public MemberDto findByMemberId(String memberId) { return MemberDto.from(member); } + @Transactional public void resetPasswordByMemberId(String memberId, String newPassword) { Member member = memberRepository.findOneById(memberId); @@ -201,4 +200,20 @@ public void resetPasswordByMemberId(String memberId, String newPassword) { member.updatePassword(ConvertSHA256.convertToSHA256(newPassword)); } + @Transactional + public MemberDto loginForKakao(String accessToken) { + + KakaoUserDto kakaoUser = kakaoRequest.getKakaoUserByToken(accessToken); + if(Objects.isNull(memberRepository.findOneById(kakaoUser.id()))){ + memberRepository.save(Member.createForKakao(kakaoUser.id(), kakaoUser.email(), "kakao", Gender.OTHERS.ordinal(), Age.AGE_99.ordinal())); + } + + MemberDto memberDto = MemberDto.from(memberRepository.findOneById(kakaoUser.id())); + + String loginToken = jwt.generateToken(memberDto.id()); + + authService.saveAuthByMember(memberDto.memberNo(), ConvertSHA256.convertToSHA256(loginToken)); + + return MemberDto.fromKakao(memberDto, loginToken); + } } diff --git a/module-api/src/test/java/com/kernel360/auth/controller/AuthControllerTest.java b/module-api/src/test/java/com/kernel360/auth/controller/AuthControllerTest.java index aaf111b7..5616379f 100644 --- a/module-api/src/test/java/com/kernel360/auth/controller/AuthControllerTest.java +++ b/module-api/src/test/java/com/kernel360/auth/controller/AuthControllerTest.java @@ -8,6 +8,8 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.restdocs.payload.JsonFieldType; +import static com.kernel360.common.utils.RestDocumentUtils.getDocumentRequest; +import static com.kernel360.common.utils.RestDocumentUtils.getDocumentResponse; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.*; @@ -36,6 +38,8 @@ class AuthControllerTest extends ControllerTest { .andExpect(jsonPath("$.code").value("BAC001")) .andExpect(jsonPath("$.message").value("JWT 토큰 재발급 성공")) .andDo(document("auth/reissuanceJWT", + getDocumentRequest(), + getDocumentResponse(), responseFields( fieldWithPath("status").description("상태 코드"), fieldWithPath("message").description("응답 메시지"), diff --git a/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java b/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java index 9bb9a399..829802ff 100644 --- a/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java +++ b/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java @@ -31,7 +31,7 @@ class MemberControllerTest extends ControllerTest { void 회원가입요청() throws Exception { /** given 목데이터 세팅 **/ - MemberDto memberDto = MemberDto.of("testID", "gunsight777@naver.com", "testPassword", "man", "30"); + MemberDto memberDto = MemberDto.of("testID", "gunsight777@naver.com", "testPassword", "MALE", "30"); ObjectMapper objectMapper = new ObjectMapper(); String param = objectMapper.writeValueAsString(memberDto); diff --git a/module-domain/src/main/java/com/kernel360/member/entity/Member.java b/module-domain/src/main/java/com/kernel360/member/entity/Member.java index d85ea85c..d27a8380 100644 --- a/module-domain/src/main/java/com/kernel360/member/entity/Member.java +++ b/module-domain/src/main/java/com/kernel360/member/entity/Member.java @@ -41,7 +41,6 @@ public class Member extends BaseEntity { @Column(name = "age") private int age; - public static Member of(Long memberNo, String id, String email, String password, int gender, int age) { return new Member(memberNo, id, email, password, gender, age); @@ -125,4 +124,10 @@ public void updateCarInfo(CarInfo carInfo) { this.carInfo = carInfo; } + public static Member createForKakao(String id, String email, String password, int gender, int age) { + + return new Member(id, email, password, gender, age); + } + + } \ No newline at end of file