Skip to content

Commit

Permalink
feat: 최초 로그인 시 관련 정보를 함께 Response에 전달
Browse files Browse the repository at this point in the history
  • Loading branch information
Mingyum-Kim committed Sep 8, 2023
1 parent 1454fce commit 43ede9b
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 26 deletions.
22 changes: 14 additions & 8 deletions src/main/java/com/backend/auth/application/OAuthService.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.backend.auth.application;

import com.backend.auth.jwt.TokenProvider;
import com.backend.auth.presentation.dto.response.TokenResponse;
import com.backend.auth.presentation.dto.response.LoginResponse;
import com.backend.auth.presentation.dto.response.ReissueResponse;
import com.backend.member.application.MemberService;
import com.backend.member.domain.Provider;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,19 +24,24 @@ public class OAuthService {

private final FcmTokenService fcmTokenService;

public TokenResponse login(String provider, String uid, String fcmToken) {
memberService.findMemberOrRegister(Provider.from(provider), uid);
public LoginResponse login(String provider, String uid, String fcmToken) {
Boolean isFirstLogin = memberService.findMemberOrRegister(Provider.from(provider), uid);

String accessToken = tokenProvider.generateAccessToken(uid);
String refreshToken = tokenProvider.generateRefreshToken(uid);

if(!isFirstLogin) { // 재로그인 시, 기존에 저장된 정보를 삭제한다.
refreshTokenService.deleteByUid(uid);
fcmTokenService.deleteByUid(uid);
}

refreshTokenService.saveRefreshToken(uid, refreshToken);
fcmTokenService.saveFcmToken(uid, fcmToken);

return new TokenResponse(accessToken, refreshToken);
return new LoginResponse(isFirstLogin, accessToken, refreshToken);
}

public TokenResponse reissue(String bearerRefreshToken) throws Exception {
public ReissueResponse reissue(String bearerRefreshToken) throws Exception {
String refreshToken = tokenProvider.getToken(bearerRefreshToken);

log.info("refresh token : " + refreshToken);
Expand All @@ -47,10 +53,10 @@ public TokenResponse reissue(String bearerRefreshToken) throws Exception {
refreshTokenService.deleteByUid(uid);
refreshTokenService.saveRefreshToken(uid, renewRefreshToken);

return new TokenResponse(renewAccessToken, renewRefreshToken);
return new ReissueResponse(renewAccessToken, renewRefreshToken);
}

public void logout(String bearerAccessToken) throws Exception {
public void logout(String bearerAccessToken) {
String accessToken = tokenProvider.getToken(bearerAccessToken);
String uid = tokenProvider.getPayload(accessToken);

Expand All @@ -61,7 +67,7 @@ public void logout(String bearerAccessToken) throws Exception {
blackListService.saveBlackList(accessToken, expiration);
}

public void withdraw(String bearerAccessToken) throws Exception {
public void withdraw(String bearerAccessToken) {
String accessToken = tokenProvider.getToken(bearerAccessToken);

String uid = tokenProvider.getPayload(accessToken);
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/com/backend/auth/presentation/OAuthController.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.backend.auth.presentation;

import com.backend.auth.application.OAuthService;
import com.backend.auth.presentation.dto.LoginRequestDto;
import com.backend.auth.presentation.dto.response.TokenResponse;
import com.backend.auth.presentation.dto.request.LoginRequestDto;
import com.backend.auth.presentation.dto.response.LoginResponse;
import com.backend.auth.presentation.dto.response.ReissueResponse;
import com.backend.global.common.response.CustomResponse;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
Expand All @@ -27,7 +28,7 @@ public class OAuthController {
@Operation(summary = "소셜 로그인",
description = "카카오, 애플 서버에서 로그인한 사용자의 userId를 통해 access token과 refresh token을 반환합니다.")
@PostMapping("/{provider}")
public ResponseEntity<CustomResponse<TokenResponse>> login (
public ResponseEntity<CustomResponse<LoginResponse>> login (
@Parameter(description = "kakao, apple 중 현재 로그인하는 소셜 타입", in = ParameterIn.PATH) @PathVariable String provider,
@RequestBody LoginRequestDto loginRequestDto) {
return CustomResponse.success(LOGIN_SUCCESS, oauthService.login(provider, loginRequestDto.userId(), loginRequestDto.fcmToken()));
Expand All @@ -37,7 +38,7 @@ public ResponseEntity<CustomResponse<TokenResponse>> login (
description = "access token 만료 시 refresh token을 통해 access token을 재발급합니다.")
@PostMapping("/reissue")
@ExceptionHandler({UnsupportedJwtException.class, MalformedJwtException.class, IllegalArgumentException.class})
public ResponseEntity<CustomResponse<TokenResponse>> reissue(@RequestHeader(value = "Authorization") String bearerRefreshToken) throws Exception {
public ResponseEntity<CustomResponse<ReissueResponse>> reissue(@RequestHeader(value = "Authorization") String bearerRefreshToken) throws Exception {
return CustomResponse.success(LOGIN_SUCCESS, oauthService.reissue(bearerRefreshToken));
}

Expand All @@ -54,4 +55,5 @@ public ResponseEntity<CustomResponse<Void>> withdraw(@RequestHeader(value = "Aut
oauthService.withdraw(bearerAccessToken);
return CustomResponse.success(DELETE_SUCCESS);
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.backend.auth.presentation.dto;
package com.backend.auth.presentation.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import io.swagger.v3.oas.annotations.media.Schema;

public record TokenResponse(
public record LoginResponse(

@Schema(description = "사용자가 처음 로그인한 경우인지 확인", example = "false")
Boolean isFirstLogin,

@Schema(description = "사용자 인증 후 발급한 access token", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
String accessToken,

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.backend.auth.presentation.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;

public record ReissueResponse(
@Schema(description = "사용자 인증 후 발급한 access token", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
String accessToken,

@Schema(description = "사용자 인증 후 발급한 refresh token", example = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZ")
String refreshToken
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ public class MemberService {

private final MemberRepository memberRepository;

public Member findMemberOrRegister(Provider provider, String uid) {
public Boolean findMemberOrRegister(Provider provider, String uid) {
Optional<Member> member = memberRepository.findByUid(uid);
return member.orElseGet(() -> memberRepository.save(Member.from(provider, uid)));
if(member.isPresent()) // 기등록된 회원인 경우, 다시 저장하지 않는다.
return false;
memberRepository.save(Member.from(provider, uid));
return true;
}

public void withdraw(String uid) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jwt:
spring:
jpa:
hibernate:
ddl-auto: none
ddl-auto: create
database-platform: org.hibernate.dialect.H2Dialect
properties:
hibernate:
Expand Down
23 changes: 14 additions & 9 deletions src/test/java/com/backend/auth/application/OAuthServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.backend.auth.application;

import com.backend.auth.presentation.dto.response.TokenResponse;
import com.backend.auth.presentation.dto.response.LoginResponse;
import com.backend.auth.presentation.dto.response.ReissueResponse;
import com.backend.global.exception.BusinessException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -9,9 +10,9 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
Expand All @@ -35,14 +36,15 @@ public void loginSuccess() {
String provider = "kakao";

// when
TokenResponse response = oAuthService.login(provider, UID, FCM_TOKEN);
LoginResponse response = oAuthService.login(provider, UID, FCM_TOKEN);

// then
assertThat(response.accessToken()).isNotNull();
}

@DisplayName("kakao, apple 이외의 요청이 들어온 경우에 예외가 발생한다.")
@Test
@jakarta.transaction.Transactional
public void loginFailedByInvalidProvider() {
// given
String provider = "naver";
Expand All @@ -54,16 +56,17 @@ public void loginFailedByInvalidProvider() {

@DisplayName("access token이 만료되어 refresh token을 통해 재발급한다.")
@Test
@Transactional
public void reissueRefreshToken() throws Exception {
// given
TokenResponse tokenResponse = oAuthService.login("kakao", UID, FCM_TOKEN);
LoginResponse loginResponse = oAuthService.login("kakao", UID, FCM_TOKEN);

// when
TokenResponse renewTokenResponse = oAuthService.reissue(BEARER_TOKEN_PREFIX + tokenResponse.refreshToken());
ReissueResponse reissueResponse = oAuthService.reissue(BEARER_TOKEN_PREFIX + loginResponse.refreshToken());

// then
assertThat(renewTokenResponse.accessToken()).isNotNull();
assertThat(renewTokenResponse.refreshToken()).isNotNull();
assertThat(reissueResponse.accessToken()).isNotNull();
assertThat(loginResponse.refreshToken()).isNotNull();
}

@DisplayName("저장되어 있지 않은 refresh token이 입력되면 예외가 발생한다. ")
Expand All @@ -77,11 +80,13 @@ public void refreshTokenNotFound() {

@DisplayName("로그아웃을 성공적으로 완료한다.")
@Test
@Transactional
public void logoutSuccess(){
// given
TokenResponse tokenResponse = oAuthService.login("kakao", UID, FCM_TOKEN);
LoginResponse loginResponse = oAuthService.login("kakao", UID, FCM_TOKEN);

// when & then
assertThatNoException().isThrownBy(() -> oAuthService.withdraw( BEARER_TOKEN_PREFIX + tokenResponse.accessToken()));
assertDoesNotThrow(() -> oAuthService.withdraw( BEARER_TOKEN_PREFIX + loginResponse.accessToken()));
}

}

0 comments on commit 43ede9b

Please sign in to comment.