diff --git a/src/main/java/com/favoriteplace/app/member/Facade/AuthFacade.java b/src/main/java/com/favoriteplace/app/member/Facade/AuthFacade.java new file mode 100644 index 0000000..4263f8f --- /dev/null +++ b/src/main/java/com/favoriteplace/app/member/Facade/AuthFacade.java @@ -0,0 +1,72 @@ +package com.favoriteplace.app.member.Facade; + +import com.favoriteplace.app.member.controller.dto.KaKaoSignUpRequestDto; +import com.favoriteplace.app.member.controller.dto.MemberDto; +import com.favoriteplace.app.member.controller.dto.MemberSignUpReqDto; +import com.favoriteplace.app.member.controller.dto.TokenInfoDto; +import com.favoriteplace.app.member.domain.Member; +import com.favoriteplace.app.member.service.MemberService; +import com.favoriteplace.app.member.service.TokenService; +import com.favoriteplace.global.auth.kakao.KakaoClient; +import com.favoriteplace.global.auth.provider.JwtTokenProvider; + +import lombok.RequiredArgsConstructor; + +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class AuthFacade { + private final MemberService memberService; + private final TokenService tokenService; + private final JwtTokenProvider jwtTokenProvider; + private final KakaoClient kakaoClient; + + public TokenInfoDto kakaoLogin(final String token) { + String email = kakaoClient.getUserInfo(token).kakaoAccount().email(); + memberService.kakaoLogin(email); + return getTokenDto(email); + } + + public MemberDto.MemberSignUpResDto kakaoSignUp( + final String token, + final KaKaoSignUpRequestDto memberSignUpReqDto, + final List images + ) throws IOException { + String email = kakaoClient.getUserInfo(token).kakaoAccount().email(); + TokenInfoDto tokenDto = getTokenDto(email); + Member member = memberService.kakaoSignUp(email, memberSignUpReqDto, images); + tokenService.updateRefreshToken(member, tokenDto.refreshToken()); + return MemberDto.MemberSignUpResDto.from(member, tokenDto); + } + + public MemberDto.MemberSignUpResDto signup( + final MemberSignUpReqDto memberSignUpReqDto, + final List images + ) throws IOException { + Member member = memberService.signup(memberSignUpReqDto, images); + TokenInfoDto tokenDto = getTokenDto(member.getEmail()); + tokenService.updateRefreshToken(member, tokenDto.refreshToken()); + return MemberDto.MemberSignUpResDto.from(member, tokenDto); + } + + public void logout(String accessToken) { + Authentication authentication = jwtTokenProvider.getAuthentication(accessToken); + String email = authentication.getName(); + Long expiration = jwtTokenProvider.getExpiration(accessToken); + Member member = memberService.findMember(email); + tokenService.logoutAndInvalidateToken(member, expiration, accessToken); + } + + private TokenInfoDto getTokenDto(String email) { + return TokenInfoDto.of( + jwtTokenProvider.issueAccessToken(email), + jwtTokenProvider.issueRefreshToken(email) + ); + } +} diff --git a/src/main/java/com/favoriteplace/app/member/controller/MemberController.java b/src/main/java/com/favoriteplace/app/member/controller/MemberController.java index 54de6f6..8fd7afc 100644 --- a/src/main/java/com/favoriteplace/app/member/controller/MemberController.java +++ b/src/main/java/com/favoriteplace/app/member/controller/MemberController.java @@ -1,5 +1,6 @@ package com.favoriteplace.app.member.controller; +import com.favoriteplace.app.member.Facade.AuthFacade; import com.favoriteplace.app.member.controller.dto.TokenInfoDto; import com.favoriteplace.global.auth.provider.JwtTokenProvider; import com.favoriteplace.app.member.controller.dto.KaKaoSignUpRequestDto; @@ -34,8 +35,9 @@ @RequiredArgsConstructor @RequestMapping("/auth") public class MemberController { - private final MemberService memberService; + private final AuthFacade authFacade; private final MailSendService mailSendService; + private final MemberService memberService; private final JwtTokenProvider jwtTokenProvider; private final SecurityUtil securityUtil; @@ -43,7 +45,7 @@ public class MemberController { public ResponseEntity kakaoLogin( @RequestHeader("Authorization") final String token ) { - return ResponseEntity.ok(memberService.kakaoLogin(token)); + return ResponseEntity.ok(authFacade.kakaoLogin(token)); } @PostMapping("/signup/kakao") @@ -52,7 +54,7 @@ public ResponseEntity kakaoSignUp( @RequestPart(required = false) final List images, @RequestPart final KaKaoSignUpRequestDto data ) throws IOException { - return ResponseEntity.ok(memberService.kakaoSignUp(token, data, images)); + return ResponseEntity.ok(authFacade.kakaoSignUp(token, data, images)); } @PostMapping("/signup") @@ -60,7 +62,7 @@ public ResponseEntity signup( @RequestPart(required = false) List images, @RequestPart MemberSignUpReqDto data ) throws IOException { - return ResponseEntity.ok(memberService.signup(data, images)); + return ResponseEntity.ok(authFacade.signup(data, images)); } @PostMapping("/signup/email") @@ -97,8 +99,7 @@ public ResponseEntity setNewPassword( @PostMapping("/logout") public ResponseEntity logout(HttpServletRequest request) { String accessToken = securityUtil.resolveToken(request); - memberService.logout(accessToken); - + authFacade.logout(accessToken); return ResponseEntity.ok("로그아웃 되었습니다."); } } diff --git a/src/main/java/com/favoriteplace/app/member/domain/Member.java b/src/main/java/com/favoriteplace/app/member/domain/Member.java index 91de980..f31099d 100644 --- a/src/main/java/com/favoriteplace/app/member/domain/Member.java +++ b/src/main/java/com/favoriteplace/app/member/domain/Member.java @@ -79,7 +79,7 @@ public class Member extends BaseTimeEntity { public static Member create( String nickname, String email, boolean snsAllow, String introduction, - String profileImage, Item titleItem) + String profileImage, Item titleItem, LoginType loginType) { return Member.builder() .nickname(nickname) @@ -88,7 +88,7 @@ public static Member create( .description(introduction) .profileImageUrl(profileImage) .point(0L) - .loginType(LoginType.KAKAO) + .loginType(loginType) .profileTitle(titleItem) .status(MemberStatus.Y) .build(); diff --git a/src/main/java/com/favoriteplace/app/member/service/MailSendService.java b/src/main/java/com/favoriteplace/app/member/service/MailSendService.java index 7fed3f0..44b2e87 100644 --- a/src/main/java/com/favoriteplace/app/member/service/MailSendService.java +++ b/src/main/java/com/favoriteplace/app/member/service/MailSendService.java @@ -31,8 +31,6 @@ public class MailSendService { private final RedisUtil redisUtil; - - //임의의 6자리 양수를 반환합니다. public void makeRandomNumber() { Random r = new Random(); String randomNumber = ""; @@ -43,23 +41,21 @@ public void makeRandomNumber() { authNumber = Integer.parseInt(randomNumber); } - //mail을 어디서 보내는지, 어디로 보내는지 , 인증 번호를 html 형식으로 어떻게 보내는지 작성합니다. public MemberDto.EmailSendResDto joinEmail(String email) { makeRandomNumber(); String setFrom = host; // email-config에 설정한 자신의 이메일 주소를 입력 String toMail = email; - String title = "[최애의 장소] 회원 가입 인증 이메일 입니다."; // 이메일 제목 + String title = "[최애의 장소] 회원 가입 인증 이메일 입니다."; String content = - "최애의 장소를 방문해주셔서 감사합니다." + //html 형식으로 작성 ! + "최애의 장소를 방문해주셔서 감사합니다." + "

" + "인증 번호는 " + authNumber + "입니다." + "
" + - "인증번호를 올바르게 입력해주세요 :)"; //이메일 내용 삽입 + "인증번호를 올바르게 입력해주세요 :)"; mailSend(setFrom, toMail, title, content); return new MemberDto.EmailSendResDto(authNumber); } - //이메일을 전송합니다. public void mailSend(String setFrom, String toMail, String title, String content) { //JavaMailSender 객체를 사용하여 MimeMessage 객체를 생성 MimeMessage message = mailSender.createMimeMessage(); diff --git a/src/main/java/com/favoriteplace/app/member/service/MemberService.java b/src/main/java/com/favoriteplace/app/member/service/MemberService.java index 82778a2..ecfc627 100644 --- a/src/main/java/com/favoriteplace/app/member/service/MemberService.java +++ b/src/main/java/com/favoriteplace/app/member/service/MemberService.java @@ -1,11 +1,9 @@ package com.favoriteplace.app.member.service; -import static com.favoriteplace.global.exception.ErrorCode.TOKEN_NOT_VALID; import static com.favoriteplace.global.exception.ErrorCode.USER_ALREADY_EXISTS; import static com.favoriteplace.global.exception.ErrorCode.USER_NOT_FOUND; import com.favoriteplace.app.member.controller.dto.MemberSignUpReqDto; -import com.favoriteplace.app.member.controller.dto.TokenInfoDto; import com.favoriteplace.app.member.domain.Member; import com.favoriteplace.app.item.domain.Item; import com.favoriteplace.app.member.controller.dto.UserInfoResponseDto; @@ -14,6 +12,7 @@ import com.favoriteplace.app.member.controller.dto.MemberDto.EmailDuplicateResDto; import com.favoriteplace.app.member.controller.dto.MemberDto.EmailSendReqDto; import com.favoriteplace.app.item.repository.ItemRepository; +import com.favoriteplace.app.member.domain.enums.LoginType; import com.favoriteplace.app.member.repository.MemberRepository; import com.favoriteplace.global.auth.kakao.KakaoClient; import com.favoriteplace.global.auth.provider.JwtTokenProvider; @@ -22,12 +21,11 @@ import java.io.IOException; import java.util.List; -import java.util.concurrent.TimeUnit; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -36,74 +34,55 @@ @Service @Transactional(readOnly = true) @RequiredArgsConstructor +@Slf4j public class MemberService { private final MemberRepository memberRepository; private final PasswordEncoder passwordEncoder; - private final JwtTokenProvider jwtTokenProvider; private final AmazonS3ImageManager amazonS3ImageManager; private final ItemRepository itemRepository; - private final RedisTemplate redisTemplate; - private final KakaoClient kakaoClient; - public TokenInfoDto kakaoLogin(final String token) { - String userEmail = getUserEmailFromKakao(token); - - // 최초 로그인이라면 회원가입 API로 통신하도록 - Member member = findMember(userEmail); - - return issueToken(userEmail); + public void kakaoLogin(final String email) { + Member member = findMember(email); } @Transactional - public MemberDto.MemberSignUpResDto kakaoSignUp( - final String token, + public Member kakaoSignUp( + final String email, final KaKaoSignUpRequestDto memberSignUpReqDto, final List images ) throws IOException { - - String userEmail = getUserEmailFromKakao(token); - - memberRepository.findByEmail(userEmail) + memberRepository.findByEmail(email) .ifPresent(a -> { throw new RestApiException(USER_ALREADY_EXISTS); }); - String profileImage = getProfileImageFromRequest(images); - Item titleItem = getDefaultProfileItem(); - - Member member = saveUser(memberSignUpReqDto.nickname(), userEmail, - memberSignUpReqDto.snsAllow(), memberSignUpReqDto.introduction(), - profileImage, titleItem); - - TokenInfoDto tokenInfo = issueToken(userEmail); - member.updateRefreshToken(tokenInfo.refreshToken()); - - return MemberDto.MemberSignUpResDto.from(member, tokenInfo); - + Member member = saveUser( + memberSignUpReqDto.nickname(), + email, + memberSignUpReqDto.snsAllow(), + memberSignUpReqDto.introduction(), + profileImage, + titleItem, + LoginType.KAKAO + ); + return member; } @Transactional - public MemberDto.MemberSignUpResDto signup( + public Member signup( final MemberSignUpReqDto memberSignUpReqDto, final List images ) throws IOException { - String password = passwordEncoder.encode(memberSignUpReqDto.password()); - Item titleItem = getDefaultProfileItem(); - String profileImage = getProfileImageFromRequest(images); - Member member = saveUser(memberSignUpReqDto.nickname(), memberSignUpReqDto.email(), memberSignUpReqDto.snsAllow(), memberSignUpReqDto.introduction(), - profileImage, titleItem); - - TokenInfoDto tokenInfo= issueToken(member.getEmail()); - member.updateRefreshToken(tokenInfo.refreshToken()); - - return MemberDto.MemberSignUpResDto.from(member, tokenInfo); + profileImage, titleItem, LoginType.SELF); + member.updatePassword(password); + return member; } public String uploadProfileImage(MultipartFile profileImage) throws IOException { @@ -113,14 +92,12 @@ public String uploadProfileImage(MultipartFile profileImage) throws IOException public MemberDto.EmailDuplicateResDto emailDuplicateCheck(EmailSendReqDto emailSendReqDto) { String email = emailSendReqDto.getEmail(); Boolean isExists = memberRepository.findByEmail(email).isPresent(); - return new EmailDuplicateResDto(isExists); } @Transactional public void setNewPassword(String email, String password) { Member member = findMember(email); - String newPassword = passwordEncoder.encode(password); member.updatePassword(newPassword); } @@ -132,49 +109,25 @@ public UserInfoResponseDto getUserInfo(Member member) { return null; } - @Transactional - public void logout(String accessToken) { - /*1. Access Token 검증 */ - if (!jwtTokenProvider.validateToken(accessToken)) { - new RestApiException(TOKEN_NOT_VALID); - } - - Authentication authentication = jwtTokenProvider.getAuthentication(accessToken); - Member member = findMember(authentication.getName()); - - if (member.getRefreshToken() != null && !member.getRefreshToken().isEmpty()) { - member.deleteRefreshToken(member.getRefreshToken()); - } - - /* 해당 asscess token 유효시간을 계산해서 blacklist로 저장 */ - Long expriation = jwtTokenProvider.getExpiration(accessToken); - redisTemplate.opsForValue() - .set(accessToken, "logout", expriation, TimeUnit.MICROSECONDS); - } - - private Member findMember(final String email) { + public Member findMember(final String email) { return memberRepository.findByEmail(email) .orElseThrow(() -> new RestApiException(USER_NOT_FOUND)); } - private String getUserEmailFromKakao(String token) { - return kakaoClient.getUserInfo(token).kakaoAccount().email(); - } - private Item getDefaultProfileItem() { return itemRepository.findByName("새싹회원").get(); } - private TokenInfoDto issueToken(String email) { - return jwtTokenProvider.generateToken(email); - } - private Member saveUser( String nickname, String email, boolean snsAllow, String introduction, - String profileImage, Item titleItem) - { - Member member = Member.create(nickname, email, snsAllow, introduction, profileImage, titleItem); + String profileImage, Item titleItem, LoginType loginType) { + Member member = + Member.create( + nickname, email, + snsAllow, introduction, + profileImage, titleItem, loginType + ); return memberRepository.save(member); } diff --git a/src/main/java/com/favoriteplace/app/member/service/TokenService.java b/src/main/java/com/favoriteplace/app/member/service/TokenService.java new file mode 100644 index 0000000..9ef32e1 --- /dev/null +++ b/src/main/java/com/favoriteplace/app/member/service/TokenService.java @@ -0,0 +1,41 @@ +package com.favoriteplace.app.member.service; + +import com.favoriteplace.app.member.domain.Member; +import com.favoriteplace.global.auth.provider.JwtTokenProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +import java.util.concurrent.TimeUnit; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class TokenService { + private final RedisTemplate redisTemplate; + + @Transactional + public void updateRefreshToken(Member member, String refreshToken) { + member.updateRefreshToken(refreshToken); + } + + @Transactional + public void logoutAndInvalidateToken(Member member, Long expiration, String accessToken) { + deleteRefreshToken(member); + blacklistAccessToken(expiration, accessToken); + } + + private void deleteRefreshToken (Member member) { + if (member.getRefreshToken() != null && !member.getRefreshToken().isEmpty()) { + member.deleteRefreshToken(member.getRefreshToken()); + } + } + + private void blacklistAccessToken(Long expiration, String accessToken) { + redisTemplate.opsForValue() + .set(accessToken, "logout", expiration, TimeUnit.MICROSECONDS); + } + +} diff --git a/src/main/java/com/favoriteplace/global/auth/handler/CustomAuthenticationSuccessHandler.java b/src/main/java/com/favoriteplace/global/auth/handler/CustomAuthenticationSuccessHandler.java index 8da0d20..b0d1d68 100644 --- a/src/main/java/com/favoriteplace/global/auth/handler/CustomAuthenticationSuccessHandler.java +++ b/src/main/java/com/favoriteplace/global/auth/handler/CustomAuthenticationSuccessHandler.java @@ -43,8 +43,10 @@ public void onAuthenticationSuccess( Member member = memberRepository.findByEmail(email) .orElseThrow(() -> new RestApiException(ErrorCode.USER_NOT_FOUND)); - TokenInfoDto tokenInfo = jwtTokenProvider.generateToken(member.getEmail()); + String issuedRefreshToken = jwtTokenProvider.issueRefreshToken(member.getEmail()); + String issuedAccessToken = jwtTokenProvider.issueRefreshToken(member.getEmail()); + TokenInfoDto tokenInfo = TokenInfoDto.of(issuedAccessToken, issuedRefreshToken); member.updateRefreshToken(tokenInfo.refreshToken()); response.setContentType(APPLICATION_JSON_VALUE); diff --git a/src/main/java/com/favoriteplace/global/auth/provider/JwtTokenProvider.java b/src/main/java/com/favoriteplace/global/auth/provider/JwtTokenProvider.java index 26bd0e0..eddbf3f 100644 --- a/src/main/java/com/favoriteplace/global/auth/provider/JwtTokenProvider.java +++ b/src/main/java/com/favoriteplace/global/auth/provider/JwtTokenProvider.java @@ -41,25 +41,12 @@ public class JwtTokenProvider { @Value("${jwt.secret}") private String key; - public TokenInfoDto generateToken(String userEmail) { - String accessToken = issueToken(userEmail, ACCESS_TOKEN_EXPIRATION_TIME); - String refreshToken = issueToken(userEmail, REFRESH_TOKEN_EXPIRATION_TIME); - - return TokenInfoDto.of(accessToken, refreshToken); + public String issueRefreshToken(String userEmail) { + return issueToken(userEmail, REFRESH_TOKEN_EXPIRATION_TIME); } - public String issueToken(String userEmail, Long expirePeriod) { - Claims claims = Jwts.claims().setSubject(userEmail); - Date now = new Date(); - - String refreshToken = Jwts.builder() - .setClaims(claims) - .setIssuedAt(now) - .setExpiration(new Date(now.getTime() + expirePeriod)) - .signWith(SignatureAlgorithm.HS256, key) - .compact(); - - return refreshToken; + public String issueAccessToken(String userEmail) { + return issueToken(userEmail, ACCESS_TOKEN_EXPIRATION_TIME); } public Authentication getAuthentication(String token) { @@ -76,10 +63,9 @@ public Long getExpiration(String token) { return (expiration.getTime() - now); } - public boolean validateToken(String token) { + public void validateToken(String token) { try { parseClaims(token); - return true; } catch (MalformedJwtException e) { throw new RestApiException(INVALID_JWT); } catch (ExpiredJwtException e) { @@ -95,4 +81,18 @@ private Claims parseClaims(String token) { return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody(); } + private String issueToken(String userEmail, Long expirePeriod) { + Claims claims = Jwts.claims().setSubject(userEmail); + Date now = new Date(); + + String token = Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(new Date(now.getTime() + expirePeriod)) + .signWith(SignatureAlgorithm.HS256, key) + .compact(); + + return token; + } + } diff --git a/src/main/java/com/favoriteplace/global/util/RedisUtil.java b/src/main/java/com/favoriteplace/global/util/RedisUtil.java index 8e5fc36..2544df0 100644 --- a/src/main/java/com/favoriteplace/global/util/RedisUtil.java +++ b/src/main/java/com/favoriteplace/global/util/RedisUtil.java @@ -2,6 +2,7 @@ import java.time.Duration; import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Service; @@ -9,17 +10,17 @@ @Service @RequiredArgsConstructor public class RedisUtil { - private final StringRedisTemplate redisTemplate;//Redis에 접근하기 위한 Spring의 Redis 템플릿 클래스 + private final RedisTemplate redisTemplate; - public String getData(String key){//지정된 키(key)에 해당하는 데이터를 Redis에서 가져오는 메서드 + public String getData(String key){ ValueOperations valueOperations = redisTemplate.opsForValue(); return valueOperations.get(key); } - public void setData(String key, String value){//지정된 키(key)에 값을 저장하는 메서드 + public void setData(String key, String value){ ValueOperations valueOperations = redisTemplate.opsForValue(); valueOperations.set(key, value); } - public void setDataExpire(String key, String value, long duration){//지정된 키(key)에 값을 저장하고, 지정된 시간(duration) 후에 데이터가 만료되도록 설정하는 메서드 + public void setDataExpire(String key, String value, long duration){ ValueOperations valueOperations = redisTemplate.opsForValue(); Duration expireDuration = Duration.ofSeconds(duration); valueOperations.set(key, value, expireDuration); diff --git a/src/main/java/com/favoriteplace/global/websocket/JwtChannelInterceptor.java b/src/main/java/com/favoriteplace/global/websocket/JwtChannelInterceptor.java index 68199e6..e9563a5 100644 --- a/src/main/java/com/favoriteplace/global/websocket/JwtChannelInterceptor.java +++ b/src/main/java/com/favoriteplace/global/websocket/JwtChannelInterceptor.java @@ -51,10 +51,7 @@ public Message preSend(Message message, MessageChannel channel) { String jwt = bearerToken.startsWith("Bearer ") ? bearerToken.substring(7) : bearerToken; try { - // JWT 토큰 검증 - if (!jwtProvider.validateToken(jwt)) { - throw new RestApiException(ErrorCode.USER_NOT_AUTHOR); - } + jwtProvider.validateToken(jwt); Authentication authentication = jwtProvider.getAuthentication(jwt); diff --git a/src/test/java/com/favoriteplace/app/member/facade/AuthFacadeTest.java b/src/test/java/com/favoriteplace/app/member/facade/AuthFacadeTest.java new file mode 100644 index 0000000..7081e6c --- /dev/null +++ b/src/test/java/com/favoriteplace/app/member/facade/AuthFacadeTest.java @@ -0,0 +1,79 @@ +package com.favoriteplace.app.member.facade; + +import com.favoriteplace.app.member.Facade.AuthFacade; +import com.favoriteplace.app.member.controller.dto.AuthKakaoLoginDto; +import com.favoriteplace.app.member.controller.dto.TokenInfoDto; +import com.favoriteplace.app.member.domain.Member; +import com.favoriteplace.app.member.domain.enums.LoginType; +import com.favoriteplace.app.member.service.MemberService; +import com.favoriteplace.global.auth.kakao.KakaoClient; +import com.favoriteplace.global.auth.provider.JwtTokenProvider; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AuthFacadeTest { + + @Mock + private MemberService memberService; + + @Mock + private KakaoClient kakaoClient; + + @Mock + private JwtTokenProvider jwtTokenProvider; + + @InjectMocks + private AuthFacade authFacade; + + private static Member member; + + @BeforeEach + void setUp() { + member = Member.create( + "yoon", + "email", + true, + "자기소개", + "image", + null, + LoginType.SELF + ); + } + + @Test + @DisplayName("카카오 로그인 - 카카오로부터 사용자 정보를 받아오고, 토큰을 생성하여 반환한다.") + void kakaoLoginTest() { + // given + when(kakaoClient.getUserInfo(anyString())) + .thenReturn(new AuthKakaoLoginDto(new AuthKakaoLoginDto.KakaoAccount("email"))); + + doNothing().when(memberService).kakaoLogin("email"); + + when(jwtTokenProvider.issueAccessToken("email")).thenReturn("accessToken"); + when(jwtTokenProvider.issueRefreshToken("email")).thenReturn("refreshToken"); + + // when + TokenInfoDto result = authFacade.kakaoLogin("kakaoAccessToken"); + + // then + assertThat(result.accessToken()).isEqualTo("accessToken"); + assertThat(result.refreshToken()).isEqualTo("refreshToken"); + + verify(kakaoClient).getUserInfo("kakaoAccessToken"); + verify(memberService).kakaoLogin("email"); + verify(jwtTokenProvider).issueAccessToken("email"); + verify(jwtTokenProvider).issueRefreshToken("email"); + } +} diff --git a/src/test/java/com/favoriteplace/app/repository/MemberRepositoryTest.java b/src/test/java/com/favoriteplace/app/repository/MemberRepositoryTest.java index 96a086b..dea441a 100644 --- a/src/test/java/com/favoriteplace/app/repository/MemberRepositoryTest.java +++ b/src/test/java/com/favoriteplace/app/repository/MemberRepositoryTest.java @@ -1,6 +1,7 @@ package com.favoriteplace.app.repository; import com.favoriteplace.app.member.domain.Member; +import com.favoriteplace.app.member.domain.enums.LoginType; import com.favoriteplace.app.member.repository.MemberRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -35,7 +36,8 @@ void setUser() { true, "자기소개", "image", - null); + null, + LoginType.SELF); } @Test