From 6fdc9c03e0985f663f9b2c526be6e26e1551f279 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 01:19:10 +0900 Subject: [PATCH 01/15] =?UTF-8?q?refactor:=20JPA=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20JPQL=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../location/country/repository/CountryRepository.java | 5 +---- .../location/region/repository/RegionRepository.java | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/example/solidconnection/location/country/repository/CountryRepository.java b/src/main/java/com/example/solidconnection/location/country/repository/CountryRepository.java index 70477f1f4..5ba92f80a 100644 --- a/src/main/java/com/example/solidconnection/location/country/repository/CountryRepository.java +++ b/src/main/java/com/example/solidconnection/location/country/repository/CountryRepository.java @@ -3,11 +3,8 @@ import com.example.solidconnection.location.country.domain.Country; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface CountryRepository extends JpaRepository { - @Query("SELECT c FROM Country c WHERE c.koreanName IN :names") - List findByKoreanNames(@Param(value = "names") List names); + List findAllByKoreanNameIn(List koreanNames); } diff --git a/src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java b/src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java index 656fc4377..dea93fb34 100644 --- a/src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java +++ b/src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java @@ -4,13 +4,10 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface RegionRepository extends JpaRepository { - @Query("SELECT r FROM Region r WHERE r.koreanName IN :names") - List findByKoreanNames(@Param(value = "names") List names); + List findAllByKoreanNameIn(List koreanNames); Optional findByKoreanName(String koreanName); } From 6abc711106a936419aa70b93714dc04b91dcd2fe Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 01:19:32 +0900 Subject: [PATCH 02/15] =?UTF-8?q?refactor:=20SignUpService=20=EB=A1=9C?= =?UTF-8?q?=EB=B6=80=ED=84=B0=20=EA=B4=80=EC=8B=AC=20=EA=B5=AD=EA=B0=80=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SignUpService의 의존성이 변하자, OAuthSignUpService와 EmailSignUpService의 코드가 변했다 -> DIP 위반 --- .../auth/service/EmailSignUpService.java | 10 ++--- .../auth/service/SignUpService.java | 39 +++++-------------- .../service/oauth/OAuthSignUpService.java | 10 ++--- .../service/InterestedCountryService.java | 25 ++++++++++++ .../service/InterestedRegionService.java | 25 ++++++++++++ 5 files changed, 70 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java create mode 100644 src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java index a3436cf5d..811faa4db 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java @@ -5,9 +5,9 @@ import com.example.solidconnection.auth.dto.SignUpRequest; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.location.country.repository.CountryRepository; -import com.example.solidconnection.location.country.repository.InterestedCountryRepository; -import com.example.solidconnection.location.region.repository.InterestedRegionRepository; +import com.example.solidconnection.location.country.service.InterestedCountryService; import com.example.solidconnection.location.region.repository.RegionRepository; +import com.example.solidconnection.location.region.service.InterestedRegionService; import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; @@ -19,10 +19,10 @@ public class EmailSignUpService extends SignUpService { private final EmailSignUpTokenProvider emailSignUpTokenProvider; public EmailSignUpService(SignInService signInService, SiteUserRepository siteUserRepository, - RegionRepository regionRepository, InterestedRegionRepository interestedRegionRepository, - CountryRepository countryRepository, InterestedCountryRepository interestedCountryRepository, + RegionRepository regionRepository, InterestedRegionService interestedRegionService, + CountryRepository countryRepository, InterestedCountryService interestedCountryService, EmailSignUpTokenProvider emailSignUpTokenProvider) { - super(signInService, siteUserRepository, regionRepository, interestedRegionRepository, countryRepository, interestedCountryRepository); + super(signInService, siteUserRepository, regionRepository, interestedRegionService, countryRepository, interestedCountryService); this.emailSignUpTokenProvider = emailSignUpTokenProvider; } diff --git a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java index aeb67d037..897132a54 100644 --- a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java @@ -5,15 +5,12 @@ import com.example.solidconnection.auth.dto.SignInResponse; import com.example.solidconnection.auth.dto.SignUpRequest; import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.location.country.domain.InterestedCountry; import com.example.solidconnection.location.country.repository.CountryRepository; -import com.example.solidconnection.location.country.repository.InterestedCountryRepository; -import com.example.solidconnection.location.region.domain.InterestedRegion; -import com.example.solidconnection.location.region.repository.InterestedRegionRepository; +import com.example.solidconnection.location.country.service.InterestedCountryService; import com.example.solidconnection.location.region.repository.RegionRepository; +import com.example.solidconnection.location.region.service.InterestedRegionService; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; -import java.util.List; import org.springframework.transaction.annotation.Transactional; /* @@ -28,19 +25,19 @@ public abstract class SignUpService { protected final SignInService signInService; protected final SiteUserRepository siteUserRepository; protected final RegionRepository regionRepository; - protected final InterestedRegionRepository interestedRegionRepository; + protected final InterestedRegionService interestedRegionService; protected final CountryRepository countryRepository; - protected final InterestedCountryRepository interestedCountryRepository; + protected final InterestedCountryService interestedCountryService; protected SignUpService(SignInService signInService, SiteUserRepository siteUserRepository, - RegionRepository regionRepository, InterestedRegionRepository interestedRegionRepository, - CountryRepository countryRepository, InterestedCountryRepository interestedCountryRepository) { + RegionRepository regionRepository, InterestedRegionService interestedRegionService, + CountryRepository countryRepository, InterestedCountryService interestedCountryService) { this.signInService = signInService; this.siteUserRepository = siteUserRepository; this.regionRepository = regionRepository; - this.interestedRegionRepository = interestedRegionRepository; + this.interestedRegionService = interestedRegionService; this.countryRepository = countryRepository; - this.interestedCountryRepository = interestedCountryRepository; + this.interestedCountryService = interestedCountryService; } @Transactional @@ -54,8 +51,8 @@ public SignInResponse signUp(SignUpRequest signUpRequest) { SiteUser siteUser = siteUserRepository.save(createSiteUser(signUpRequest)); // 관심 지역, 국가 저장 - saveInterestedRegion(signUpRequest, siteUser); - saveInterestedCountry(signUpRequest, siteUser); + interestedRegionService.saveInterestedRegion(siteUser, signUpRequest.interestedRegions()); + interestedCountryService.saveInterestedCountry(siteUser, signUpRequest.interestedCountries()); // 로그인 return signInService.signIn(siteUser); @@ -67,22 +64,6 @@ private void validateNicknameDuplicated(String nickname) { } } - private void saveInterestedRegion(SignUpRequest signUpRequest, SiteUser savedSiteUser) { - List interestedRegionNames = signUpRequest.interestedRegions(); - List interestedRegions = regionRepository.findByKoreanNames(interestedRegionNames).stream() - .map(region -> new InterestedRegion(savedSiteUser, region)) - .toList(); - interestedRegionRepository.saveAll(interestedRegions); - } - - private void saveInterestedCountry(SignUpRequest signUpRequest, SiteUser savedSiteUser) { - List interestedCountryNames = signUpRequest.interestedCountries(); - List interestedCountries = countryRepository.findByKoreanNames(interestedCountryNames).stream() - .map(country -> new InterestedCountry(savedSiteUser, country)) - .toList(); - interestedCountryRepository.saveAll(interestedCountries); - } - protected abstract void validateSignUpToken(SignUpRequest signUpRequest); protected abstract void validateUserNotDuplicated(SignUpRequest signUpRequest); diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java index ca50442fc..63e5c847f 100644 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java @@ -7,9 +7,9 @@ import com.example.solidconnection.auth.service.SignUpService; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.location.country.repository.CountryRepository; -import com.example.solidconnection.location.country.repository.InterestedCountryRepository; -import com.example.solidconnection.location.region.repository.InterestedRegionRepository; +import com.example.solidconnection.location.country.service.InterestedCountryService; import com.example.solidconnection.location.region.repository.RegionRepository; +import com.example.solidconnection.location.region.service.InterestedRegionService; import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; @@ -21,10 +21,10 @@ public class OAuthSignUpService extends SignUpService { private final OAuthSignUpTokenProvider oAuthSignUpTokenProvider; OAuthSignUpService(SignInService signInService, SiteUserRepository siteUserRepository, - RegionRepository regionRepository, InterestedRegionRepository interestedRegionRepository, - CountryRepository countryRepository, InterestedCountryRepository interestedCountryRepository, + RegionRepository regionRepository, InterestedRegionService interestedRegionService, + CountryRepository countryRepository, InterestedCountryService interestedCountryService, OAuthSignUpTokenProvider oAuthSignUpTokenProvider) { - super(signInService, siteUserRepository, regionRepository, interestedRegionRepository, countryRepository, interestedCountryRepository); + super(signInService, siteUserRepository, regionRepository, interestedRegionService, countryRepository, interestedCountryService); this.oAuthSignUpTokenProvider = oAuthSignUpTokenProvider; } diff --git a/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java b/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java new file mode 100644 index 000000000..1fca11b5d --- /dev/null +++ b/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java @@ -0,0 +1,25 @@ +package com.example.solidconnection.location.country.service; + +import com.example.solidconnection.location.country.domain.InterestedCountry; +import com.example.solidconnection.location.country.repository.CountryRepository; +import com.example.solidconnection.location.country.repository.InterestedCountryRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class InterestedCountryService { + + private final CountryRepository countryRepository; + private final InterestedCountryRepository interestedCountryRepository; + + public void saveInterestedCountry(SiteUser siteUser, List koreanNames) { + List interestedCountries = countryRepository.findAllByKoreanNameIn(koreanNames) + .stream() + .map(country -> new InterestedCountry(siteUser, country)) + .toList(); + interestedCountryRepository.saveAll(interestedCountries); + } +} diff --git a/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java b/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java new file mode 100644 index 000000000..2a6ae3c6e --- /dev/null +++ b/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java @@ -0,0 +1,25 @@ +package com.example.solidconnection.location.region.service; + +import com.example.solidconnection.location.region.domain.InterestedRegion; +import com.example.solidconnection.location.region.repository.InterestedRegionRepository; +import com.example.solidconnection.location.region.repository.RegionRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class InterestedRegionService { + + private final RegionRepository regionRepository; + private final InterestedRegionRepository interestedRegionRepository; + + public void saveInterestedRegion(SiteUser siteUser, List koreanNames) { + List interestedRegions = regionRepository.findAllByKoreanNameIn(koreanNames) + .stream() + .map(region -> new InterestedRegion(siteUser, region)) + .toList(); + interestedRegionRepository.saveAll(interestedRegions); + } +} From 10501d09d1aeee84e75c285ca5266c8aba697f91 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 02:31:12 +0900 Subject: [PATCH 03/15] =?UTF-8?q?refactor:=20'SignUpToken=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC'=EB=A7=8C=20=EB=8B=B4=EB=8B=B9=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...SignUpTokenProvider.java => SignUpTokenProvider.java} | 9 ++++----- .../solidconnection/auth/service/oauth/OAuthService.java | 5 +++-- 2 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/com/example/solidconnection/auth/service/{oauth/OAuthSignUpTokenProvider.java => SignUpTokenProvider.java} (91%) diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/SignUpTokenProvider.java similarity index 91% rename from src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java rename to src/main/java/com/example/solidconnection/auth/service/SignUpTokenProvider.java index ae359c5b8..a8ecd574b 100644 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/SignUpTokenProvider.java @@ -1,10 +1,9 @@ -package com.example.solidconnection.auth.service.oauth; +package com.example.solidconnection.auth.service; import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_INVALID; import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_NOT_ISSUED_BY_SERVER; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.AuthType; @@ -21,9 +20,9 @@ @Component @RequiredArgsConstructor -public class OAuthSignUpTokenProvider { +public class SignUpTokenProvider { - static final String AUTH_TYPE_CLAIM_KEY = "authType"; + private static final String AUTH_TYPE_CLAIM_KEY = "authType"; private final JwtProperties jwtProperties; private final RedisTemplate redisTemplate; @@ -50,7 +49,7 @@ public void validateSignUpToken(String token) { validateIssuedByServer(email); } - private void validateFormatAndExpiration(String token) { + private void validateFormatAndExpiration(String token) { // 파싱되는지, AuthType이 포함되어있는지 검증 try { Claims claims = tokenProvider.parseClaims(token); Objects.requireNonNull(claims.getSubject()); diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthService.java b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthService.java index bb34a3739..9343bfa21 100644 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthService.java +++ b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthService.java @@ -7,6 +7,7 @@ import com.example.solidconnection.auth.dto.oauth.OAuthUserInfoDto; import com.example.solidconnection.auth.dto.oauth.SignUpPrepareResponse; import com.example.solidconnection.auth.service.SignInService; +import com.example.solidconnection.auth.service.SignUpTokenProvider; import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; @@ -24,7 +25,7 @@ @RequiredArgsConstructor public class OAuthService { - private final OAuthSignUpTokenProvider OAuthSignUpTokenProvider; + private final SignUpTokenProvider signUpTokenProvider; private final SignInService signInService; private final SiteUserRepository siteUserRepository; private final OAuthClientMap oauthClientMap; @@ -49,7 +50,7 @@ private OAuthSignInResponse getSignInResponse(SiteUser siteUser) { } private SignUpPrepareResponse getSignUpPrepareResponse(OAuthUserInfoDto userInfoDto, AuthType authType) { - String signUpToken = OAuthSignUpTokenProvider.generateAndSaveSignUpToken(userInfoDto.getEmail(), authType); + String signUpToken = signUpTokenProvider.generateAndSaveSignUpToken(userInfoDto.getEmail(), authType); return SignUpPrepareResponse.of(userInfoDto, signUpToken); } } From 82a39db06d3f1527de60715456c17e2e2d3b3150 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 02:32:48 +0900 Subject: [PATCH 04/15] =?UTF-8?q?refactor:=20SignUpTokenProvider=EB=A5=BC?= =?UTF-8?q?=20=EC=A1=B0=ED=95=A9=ED=95=98=EC=97=AC=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/AuthController.java | 3 +- .../service/EmailSignUpTokenProvider.java | 76 ++++--------------- 2 files changed, 15 insertions(+), 64 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/controller/AuthController.java b/src/main/java/com/example/solidconnection/auth/controller/AuthController.java index 085343dfd..ba2d878fb 100644 --- a/src/main/java/com/example/solidconnection/auth/controller/AuthController.java +++ b/src/main/java/com/example/solidconnection/auth/controller/AuthController.java @@ -85,8 +85,7 @@ public ResponseEntity signInWithEmail( public ResponseEntity signUpWithEmail( @Valid @RequestBody EmailSignUpTokenRequest signUpRequest ) { - emailSignUpService.validateUniqueEmail(signUpRequest.email()); - String signUpToken = emailSignUpTokenProvider.generateAndSaveSignUpToken(signUpRequest); + String signUpToken = emailSignUpTokenProvider.issueEmailSignUpToken(signUpRequest); return ResponseEntity.ok(new EmailSignUpTokenResponse(signUpToken)); } diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java index 238c7e517..eed8b8820 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java @@ -1,22 +1,12 @@ package com.example.solidconnection.auth.service; -import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_INVALID; -import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_NOT_ISSUED_BY_SERVER; - import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.auth.dto.EmailSignUpTokenRequest; -import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.common.exception.ErrorCode; import com.example.solidconnection.siteuser.domain.AuthType; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; @@ -24,65 +14,27 @@ @RequiredArgsConstructor public class EmailSignUpTokenProvider { - static final String PASSWORD_CLAIM_KEY = "password"; - static final String AUTH_TYPE_CLAIM_KEY = "authType"; - private final PasswordEncoder passwordEncoder; - private final JwtProperties jwtProperties; - private final RedisTemplate redisTemplate; private final TokenProvider tokenProvider; + private final SignUpTokenProvider signUpTokenProvider; + private final SiteUserRepository siteUserRepository; - public String generateAndSaveSignUpToken(EmailSignUpTokenRequest request) { + public String issueEmailSignUpToken(EmailSignUpTokenRequest request) { String email = request.email(); + if (siteUserRepository.existsByEmailAndAuthType(email, AuthType.EMAIL)) { + throw new CustomException(ErrorCode.USER_ALREADY_EXISTED); + } + + String signUpToken = signUpTokenProvider.generateAndSaveSignUpToken(email, AuthType.EMAIL); String password = request.password(); String encodedPassword = passwordEncoder.encode(password); - Map emailSignUpClaims = new HashMap<>(Map.of( - PASSWORD_CLAIM_KEY, encodedPassword, - AUTH_TYPE_CLAIM_KEY, AuthType.EMAIL - )); - Claims claims = Jwts.claims(emailSignUpClaims).setSubject(email); - Date now = new Date(); - Date expiredDate = new Date(now.getTime() + TokenType.SIGN_UP.getExpireTime()); + // todo: 비밀번호 임시 저장 로직 추가 - String signUpToken = Jwts.builder() - .setClaims(claims) - .setIssuedAt(now) - .setExpiration(expiredDate) - .signWith(SignatureAlgorithm.HS512, jwtProperties.secret()) - .compact(); return tokenProvider.saveToken(signUpToken, TokenType.SIGN_UP); } - public void validateSignUpToken(String token) { - validateFormatAndExpiration(token); - String email = parseEmail(token); - validateIssuedByServer(email); - } - - private void validateFormatAndExpiration(String token) { - try { - Claims claims = tokenProvider.parseClaims(token); - Objects.requireNonNull(claims.getSubject()); - String encodedPassword = claims.get(PASSWORD_CLAIM_KEY, String.class); - Objects.requireNonNull(encodedPassword); - } catch (Exception e) { - throw new CustomException(SIGN_UP_TOKEN_INVALID); - } - } - - private void validateIssuedByServer(String email) { - String key = TokenType.SIGN_UP.addPrefix(email); - if (redisTemplate.opsForValue().get(key) == null) { - throw new CustomException(SIGN_UP_TOKEN_NOT_ISSUED_BY_SERVER); - } - } - - public String parseEmail(String token) { - return tokenProvider.parseSubject(token); - } - - public String parseEncodedPassword(String token) { - Claims claims = tokenProvider.parseClaims(token); - return claims.get(PASSWORD_CLAIM_KEY, String.class); + public String getTemporarySavedPassword(String signUpToken) { + // todo: 임시 저장된 비밀번호를 가져오는 로직 추가 + return ""; } } From d4a121ca6c05ca8cad4999026aadd23151047ebd Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 02:33:16 +0900 Subject: [PATCH 05/15] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EA=B4=80=EB=A0=A8=20=EC=BD=94=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=ED=95=9C=20=EA=B3=B3=EC=9C=BC=EB=A1=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/AuthController.java | 15 +--- .../service/CommonSignUpTokenProvider.java | 25 ------- .../auth/service/EmailSignUpService.java | 54 -------------- .../auth/service/SignUpService.java | 72 +++++++++++-------- .../service/oauth/OAuthSignUpService.java | 51 ------------- 5 files changed, 46 insertions(+), 171 deletions(-) delete mode 100644 src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java delete mode 100644 src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java delete mode 100644 src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java diff --git a/src/main/java/com/example/solidconnection/auth/controller/AuthController.java b/src/main/java/com/example/solidconnection/auth/controller/AuthController.java index ba2d878fb..cbcd29627 100644 --- a/src/main/java/com/example/solidconnection/auth/controller/AuthController.java +++ b/src/main/java/com/example/solidconnection/auth/controller/AuthController.java @@ -11,12 +11,10 @@ import com.example.solidconnection.auth.dto.oauth.OAuthResponse; import com.example.solidconnection.auth.dto.oauth.OAuthSignInResponse; import com.example.solidconnection.auth.service.AuthService; -import com.example.solidconnection.auth.service.CommonSignUpTokenProvider; import com.example.solidconnection.auth.service.EmailSignInService; -import com.example.solidconnection.auth.service.EmailSignUpService; import com.example.solidconnection.auth.service.EmailSignUpTokenProvider; +import com.example.solidconnection.auth.service.SignUpService; import com.example.solidconnection.auth.service.oauth.OAuthService; -import com.example.solidconnection.auth.service.oauth.OAuthSignUpService; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.common.exception.ErrorCode; import com.example.solidconnection.common.resolver.AuthorizedUser; @@ -38,12 +36,10 @@ public class AuthController { private final AuthService authService; - private final OAuthSignUpService oAuthSignUpService; private final OAuthService oAuthService; + private final SignUpService signUpService; private final EmailSignInService emailSignInService; - private final EmailSignUpService emailSignUpService; private final EmailSignUpTokenProvider emailSignUpTokenProvider; - private final CommonSignUpTokenProvider commonSignUpTokenProvider; private final RefreshTokenCookieManager refreshTokenCookieManager; @PostMapping("/apple") @@ -93,12 +89,7 @@ public ResponseEntity signUpWithEmail( public ResponseEntity signUp( @Valid @RequestBody SignUpRequest signUpRequest ) { - AuthType authType = commonSignUpTokenProvider.parseAuthType(signUpRequest.signUpToken()); - if (AuthType.isEmail(authType)) { - SignInResponse signInResponse = emailSignUpService.signUp(signUpRequest); - return ResponseEntity.ok(signInResponse); - } - SignInResponse signInResponse = oAuthSignUpService.signUp(signUpRequest); + SignInResponse signInResponse = signUpService.signUp(signUpRequest); return ResponseEntity.ok(signInResponse); } diff --git a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java deleted file mode 100644 index c6930315b..000000000 --- a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.example.solidconnection.auth.service; - -import static com.example.solidconnection.auth.service.EmailSignUpTokenProvider.AUTH_TYPE_CLAIM_KEY; -import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_INVALID; - -import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.siteuser.domain.AuthType; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class CommonSignUpTokenProvider { - - private final TokenProvider tokenProvider; - - public AuthType parseAuthType(String signUpToken) { - try { - String authTypeStr = tokenProvider.parseClaims(signUpToken).get(AUTH_TYPE_CLAIM_KEY, String.class); - return AuthType.valueOf(authTypeStr); - } catch (Exception e) { - throw new CustomException(SIGN_UP_TOKEN_INVALID); - } - } -} diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java deleted file mode 100644 index 811faa4db..000000000 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpService.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.example.solidconnection.auth.service; - -import static com.example.solidconnection.common.exception.ErrorCode.USER_ALREADY_EXISTED; - -import com.example.solidconnection.auth.dto.SignUpRequest; -import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.location.country.repository.CountryRepository; -import com.example.solidconnection.location.country.service.InterestedCountryService; -import com.example.solidconnection.location.region.repository.RegionRepository; -import com.example.solidconnection.location.region.service.InterestedRegionService; -import com.example.solidconnection.siteuser.domain.AuthType; -import com.example.solidconnection.siteuser.domain.SiteUser; -import com.example.solidconnection.siteuser.repository.SiteUserRepository; -import org.springframework.stereotype.Service; - -@Service -public class EmailSignUpService extends SignUpService { - - private final EmailSignUpTokenProvider emailSignUpTokenProvider; - - public EmailSignUpService(SignInService signInService, SiteUserRepository siteUserRepository, - RegionRepository regionRepository, InterestedRegionService interestedRegionService, - CountryRepository countryRepository, InterestedCountryService interestedCountryService, - EmailSignUpTokenProvider emailSignUpTokenProvider) { - super(signInService, siteUserRepository, regionRepository, interestedRegionService, countryRepository, interestedCountryService); - this.emailSignUpTokenProvider = emailSignUpTokenProvider; - } - - public void validateUniqueEmail(String email) { - if (siteUserRepository.existsByEmailAndAuthType(email, AuthType.EMAIL)) { - throw new CustomException(USER_ALREADY_EXISTED); - } - } - - @Override - protected void validateSignUpToken(SignUpRequest signUpRequest) { - emailSignUpTokenProvider.validateSignUpToken(signUpRequest.signUpToken()); - } - - @Override - protected void validateUserNotDuplicated(SignUpRequest signUpRequest) { - String email = emailSignUpTokenProvider.parseEmail(signUpRequest.signUpToken()); - if (siteUserRepository.existsByEmailAndAuthType(email, AuthType.EMAIL)) { - throw new CustomException(USER_ALREADY_EXISTED); - } - } - - @Override - protected SiteUser createSiteUser(SignUpRequest signUpRequest) { - String email = emailSignUpTokenProvider.parseEmail(signUpRequest.signUpToken()); - String encodedPassword = emailSignUpTokenProvider.parseEncodedPassword(signUpRequest.signUpToken()); - return signUpRequest.toEmailSiteUser(email, encodedPassword); - } -} diff --git a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java index 897132a54..0e0d0f876 100644 --- a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java @@ -1,16 +1,19 @@ package com.example.solidconnection.auth.service; import static com.example.solidconnection.common.exception.ErrorCode.NICKNAME_ALREADY_EXISTED; +import static com.example.solidconnection.common.exception.ErrorCode.USER_ALREADY_EXISTED; import com.example.solidconnection.auth.dto.SignInResponse; import com.example.solidconnection.auth.dto.SignUpRequest; import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.location.country.repository.CountryRepository; import com.example.solidconnection.location.country.service.InterestedCountryService; -import com.example.solidconnection.location.region.repository.RegionRepository; import com.example.solidconnection.location.region.service.InterestedRegionService; +import com.example.solidconnection.siteuser.domain.AuthType; +import com.example.solidconnection.siteuser.domain.Role; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /* @@ -20,35 +23,39 @@ * - 관심 국가와 지역은 site_user_id를 참조하므로, 사용자 저장 후 저장한다. * - 바로 로그인하도록 액세스 토큰과 리프레시 토큰을 발급한다. * */ -public abstract class SignUpService { +@Service +@RequiredArgsConstructor +public class SignUpService { - protected final SignInService signInService; - protected final SiteUserRepository siteUserRepository; - protected final RegionRepository regionRepository; - protected final InterestedRegionService interestedRegionService; - protected final CountryRepository countryRepository; - protected final InterestedCountryService interestedCountryService; - - protected SignUpService(SignInService signInService, SiteUserRepository siteUserRepository, - RegionRepository regionRepository, InterestedRegionService interestedRegionService, - CountryRepository countryRepository, InterestedCountryService interestedCountryService) { - this.signInService = signInService; - this.siteUserRepository = siteUserRepository; - this.regionRepository = regionRepository; - this.interestedRegionService = interestedRegionService; - this.countryRepository = countryRepository; - this.interestedCountryService = interestedCountryService; - } + private final SignInService signInService; + private final SiteUserRepository siteUserRepository; + private final InterestedRegionService interestedRegionService; + private final InterestedCountryService interestedCountryService; + private final EmailSignUpTokenProvider emailSignUpTokenProvider; + private final SignUpTokenProvider signUpTokenProvider; @Transactional public SignInResponse signUp(SignUpRequest signUpRequest) { // 검증 - validateSignUpToken(signUpRequest); - validateUserNotDuplicated(signUpRequest); - validateNicknameDuplicated(signUpRequest.nickname()); + signUpTokenProvider.validateSignUpToken(signUpRequest.signUpToken()); + String email = signUpTokenProvider.parseEmail(signUpRequest.signUpToken()); + AuthType authType = signUpTokenProvider.parseAuthType(signUpRequest.signUpToken()); + validateNicknameNotDuplicated(signUpRequest.nickname()); + validateUserNotDuplicated(email, authType); + + // 임시 저장된 비밀번호 가져오기 + String password = getTemporarySavedPassword(email, authType); // 사용자 저장 - SiteUser siteUser = siteUserRepository.save(createSiteUser(signUpRequest)); + SiteUser siteUser = siteUserRepository.save(new SiteUser( + email, + signUpRequest.nickname(), + signUpRequest.profileImageUrl(), + signUpRequest.exchangeStatus(), + Role.MENTEE, + authType, + password + )); // 관심 지역, 국가 저장 interestedRegionService.saveInterestedRegion(siteUser, signUpRequest.interestedRegions()); @@ -58,15 +65,22 @@ public SignInResponse signUp(SignUpRequest signUpRequest) { return signInService.signIn(siteUser); } - private void validateNicknameDuplicated(String nickname) { + private void validateNicknameNotDuplicated(String nickname) { if (siteUserRepository.existsByNickname(nickname)) { throw new CustomException(NICKNAME_ALREADY_EXISTED); } } - protected abstract void validateSignUpToken(SignUpRequest signUpRequest); - - protected abstract void validateUserNotDuplicated(SignUpRequest signUpRequest); + private void validateUserNotDuplicated(String email, AuthType authType) { + if (siteUserRepository.existsByEmailAndAuthType(email, authType)) { + throw new CustomException(USER_ALREADY_EXISTED); + } + } - protected abstract SiteUser createSiteUser(SignUpRequest signUpRequest); + private String getTemporarySavedPassword(String email, AuthType authType) { + if (authType == AuthType.EMAIL) { + return emailSignUpTokenProvider.getTemporarySavedPassword(email); + } + return null; + } } diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java deleted file mode 100644 index 63e5c847f..000000000 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpService.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.example.solidconnection.auth.service.oauth; - -import static com.example.solidconnection.common.exception.ErrorCode.USER_ALREADY_EXISTED; - -import com.example.solidconnection.auth.dto.SignUpRequest; -import com.example.solidconnection.auth.service.SignInService; -import com.example.solidconnection.auth.service.SignUpService; -import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.location.country.repository.CountryRepository; -import com.example.solidconnection.location.country.service.InterestedCountryService; -import com.example.solidconnection.location.region.repository.RegionRepository; -import com.example.solidconnection.location.region.service.InterestedRegionService; -import com.example.solidconnection.siteuser.domain.AuthType; -import com.example.solidconnection.siteuser.domain.SiteUser; -import com.example.solidconnection.siteuser.repository.SiteUserRepository; -import org.springframework.stereotype.Service; - -@Service -public class OAuthSignUpService extends SignUpService { - - private final OAuthSignUpTokenProvider oAuthSignUpTokenProvider; - - OAuthSignUpService(SignInService signInService, SiteUserRepository siteUserRepository, - RegionRepository regionRepository, InterestedRegionService interestedRegionService, - CountryRepository countryRepository, InterestedCountryService interestedCountryService, - OAuthSignUpTokenProvider oAuthSignUpTokenProvider) { - super(signInService, siteUserRepository, regionRepository, interestedRegionService, countryRepository, interestedCountryService); - this.oAuthSignUpTokenProvider = oAuthSignUpTokenProvider; - } - - @Override - protected void validateSignUpToken(SignUpRequest signUpRequest) { - oAuthSignUpTokenProvider.validateSignUpToken(signUpRequest.signUpToken()); - } - - @Override - protected void validateUserNotDuplicated(SignUpRequest signUpRequest) { - String email = oAuthSignUpTokenProvider.parseEmail(signUpRequest.signUpToken()); - AuthType authType = oAuthSignUpTokenProvider.parseAuthType(signUpRequest.signUpToken()); - if (siteUserRepository.existsByEmailAndAuthType(email, authType)) { - throw new CustomException(USER_ALREADY_EXISTED); - } - } - - @Override - protected SiteUser createSiteUser(SignUpRequest signUpRequest) { - String email = oAuthSignUpTokenProvider.parseEmail(signUpRequest.signUpToken()); - AuthType authType = oAuthSignUpTokenProvider.parseAuthType(signUpRequest.signUpToken()); - return signUpRequest.toOAuthSiteUser(email, authType); - } -} From cadd00815cfc4677cfb74a809488c5db6ba6079b Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 02:37:53 +0900 Subject: [PATCH 06/15] =?UTF-8?q?test:=20SignUpTokenProvider=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...Test.java => SignUpTokenProviderTest.java} | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) rename src/test/java/com/example/solidconnection/auth/service/{oauth/OAuthSignUpTokenProviderTest.java => SignUpTokenProviderTest.java} (76%) diff --git a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java similarity index 76% rename from src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java rename to src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java index bd8833bb0..1793bb6cc 100644 --- a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java @@ -1,6 +1,5 @@ -package com.example.solidconnection.auth.service.oauth; +package com.example.solidconnection.auth.service; -import static com.example.solidconnection.auth.service.oauth.OAuthSignUpTokenProvider.AUTH_TYPE_CLAIM_KEY; import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_INVALID; import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_NOT_ISSUED_BY_SERVER; import static org.assertj.core.api.Assertions.assertThat; @@ -8,7 +7,6 @@ import static org.junit.jupiter.api.Assertions.assertAll; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.AuthType; @@ -27,11 +25,11 @@ import org.springframework.data.redis.core.RedisTemplate; @TestContainerSpringBootTest -@DisplayName("OAuth 회원가입 토큰 제공자 테스트") -class OAuthSignUpTokenProviderTest { +@DisplayName("회원가입 토큰 제공자 테스트") +class SignUpTokenProviderTest { @Autowired - private OAuthSignUpTokenProvider OAuthSignUpTokenProvider; + private SignUpTokenProvider signUpTokenProvider; @Autowired private TokenProvider tokenProvider; @@ -42,6 +40,8 @@ class OAuthSignUpTokenProviderTest { @Autowired private JwtProperties jwtProperties; + private final String authTypeClaimKey = "authType"; + @Test void 회원가입_토큰을_생성하고_저장한다() { // given @@ -49,12 +49,12 @@ class OAuthSignUpTokenProviderTest { AuthType authType = AuthType.KAKAO; // when - String signUpToken = OAuthSignUpTokenProvider.generateAndSaveSignUpToken(email, authType); + String signUpToken = signUpTokenProvider.generateAndSaveSignUpToken(email, authType); // then Claims claims = tokenProvider.parseClaims(signUpToken); String actualSubject = claims.getSubject(); - AuthType actualAuthType = AuthType.valueOf(claims.get(AUTH_TYPE_CLAIM_KEY, String.class)); + AuthType actualAuthType = AuthType.valueOf(claims.get(authTypeClaimKey, String.class)); String signUpTokenKey = TokenType.SIGN_UP.addPrefix(email); assertAll( () -> assertThat(actualSubject).isEqualTo(email), @@ -70,12 +70,12 @@ class 주어진_회원가입_토큰을_검증한다 { void 검증_성공한다() { // given String email = "email@test.com"; - Map claim = new HashMap<>(Map.of(AUTH_TYPE_CLAIM_KEY, AuthType.APPLE)); + Map claim = new HashMap<>(Map.of(authTypeClaimKey, AuthType.APPLE)); String validToken = createBaseJwtBuilder().setSubject(email).addClaims(claim).compact(); redisTemplate.opsForValue().set(TokenType.SIGN_UP.addPrefix(email), validToken); // when & then - assertThatCode(() -> OAuthSignUpTokenProvider.validateSignUpToken(validToken)).doesNotThrowAnyException(); + assertThatCode(() -> signUpTokenProvider.validateSignUpToken(validToken)).doesNotThrowAnyException(); } @Test @@ -84,7 +84,7 @@ class 주어진_회원가입_토큰을_검증한다 { String expiredToken = createExpiredToken(); // when & then - assertThatCode(() -> OAuthSignUpTokenProvider.validateSignUpToken(expiredToken)) + assertThatCode(() -> signUpTokenProvider.validateSignUpToken(expiredToken)) .isInstanceOf(CustomException.class) .hasMessageContaining(SIGN_UP_TOKEN_INVALID.getMessage()); } @@ -95,7 +95,7 @@ class 주어진_회원가입_토큰을_검증한다 { String notJwt = "not jwt"; // when & then - assertThatCode(() -> OAuthSignUpTokenProvider.validateSignUpToken(notJwt)) + assertThatCode(() -> signUpTokenProvider.validateSignUpToken(notJwt)) .isInstanceOf(CustomException.class) .hasMessageContaining(SIGN_UP_TOKEN_INVALID.getMessage()); } @@ -103,11 +103,11 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 정해진_형식에_맞지_않으면_예외가_발생한다_authType_클래스_불일치() { // given - Map wrongClaim = new HashMap<>(Map.of(AUTH_TYPE_CLAIM_KEY, "카카오")); + Map wrongClaim = new HashMap<>(Map.of(authTypeClaimKey, "카카오")); String wrongAuthType = createBaseJwtBuilder().addClaims(wrongClaim).compact(); // when & then - assertThatCode(() -> OAuthSignUpTokenProvider.validateSignUpToken(wrongAuthType)) + assertThatCode(() -> signUpTokenProvider.validateSignUpToken(wrongAuthType)) .isInstanceOf(CustomException.class) .hasMessageContaining(SIGN_UP_TOKEN_INVALID.getMessage()); } @@ -115,11 +115,11 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 정해진_형식에_맞지_않으면_예외가_발생한다_subject_누락() { // given - Map claim = new HashMap<>(Map.of(AUTH_TYPE_CLAIM_KEY, AuthType.APPLE)); + Map claim = new HashMap<>(Map.of(authTypeClaimKey, AuthType.APPLE)); String noSubject = createBaseJwtBuilder().addClaims(claim).compact(); // when & then - assertThatCode(() -> OAuthSignUpTokenProvider.validateSignUpToken(noSubject)) + assertThatCode(() -> signUpTokenProvider.validateSignUpToken(noSubject)) .isInstanceOf(CustomException.class) .hasMessageContaining(SIGN_UP_TOKEN_INVALID.getMessage()); } @@ -127,11 +127,11 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 우리_서버에_발급된_토큰이_아니면_예외가_발생한다() { // given - Map validClaim = new HashMap<>(Map.of(AUTH_TYPE_CLAIM_KEY, AuthType.APPLE)); + Map validClaim = new HashMap<>(Map.of(authTypeClaimKey, AuthType.APPLE)); String signUpToken = createBaseJwtBuilder().addClaims(validClaim).setSubject("email").compact(); // when & then - assertThatCode(() -> OAuthSignUpTokenProvider.validateSignUpToken(signUpToken)) + assertThatCode(() -> signUpTokenProvider.validateSignUpToken(signUpToken)) .isInstanceOf(CustomException.class) .hasMessageContaining(SIGN_UP_TOKEN_NOT_ISSUED_BY_SERVER.getMessage()); } @@ -141,12 +141,12 @@ class 주어진_회원가입_토큰을_검증한다 { void 회원가입_토큰에서_이메일을_추출한다() { // given String email = "email@test.com"; - Map claim = Map.of(AUTH_TYPE_CLAIM_KEY, AuthType.APPLE); + Map claim = Map.of(authTypeClaimKey, AuthType.APPLE); String validToken = createBaseJwtBuilder().setSubject(email).addClaims(claim).compact(); redisTemplate.opsForValue().set(TokenType.SIGN_UP.addPrefix(email), validToken); // when - String extractedEmail = OAuthSignUpTokenProvider.parseEmail(validToken); + String extractedEmail = signUpTokenProvider.parseEmail(validToken); // then assertThat(extractedEmail).isEqualTo(email); @@ -156,11 +156,11 @@ class 주어진_회원가입_토큰을_검증한다 { void 회원가입_토큰에서_인증_타입을_추출한다() { // given AuthType authType = AuthType.APPLE; - Map claim = Map.of(AUTH_TYPE_CLAIM_KEY, authType); + Map claim = Map.of(authTypeClaimKey, authType); String validToken = createBaseJwtBuilder().setSubject("email").addClaims(claim).compact(); // when - AuthType extractedAuthType = OAuthSignUpTokenProvider.parseAuthType(validToken); + AuthType extractedAuthType = signUpTokenProvider.parseAuthType(validToken); // then assertThat(extractedAuthType).isEqualTo(authType); From abe5ae5a172841c86712f096d2f29d287eeb8677 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 02:53:30 +0900 Subject: [PATCH 07/15] =?UTF-8?q?feat:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=9E=84=EC=8B=9C=20=EC=A0=80=EC=9E=A5=EC=86=8C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/EmailSignUpTokenProvider.java | 23 +++++------ .../service/PasswordTemporaryStorage.java | 41 +++++++++++++++++++ 2 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/example/solidconnection/auth/service/PasswordTemporaryStorage.java diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java index eed8b8820..91d30f164 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java @@ -1,40 +1,37 @@ package com.example.solidconnection.auth.service; -import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.auth.dto.EmailSignUpTokenRequest; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.common.exception.ErrorCode; import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.siteuser.repository.SiteUserRepository; import lombok.RequiredArgsConstructor; -import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; @Component @RequiredArgsConstructor public class EmailSignUpTokenProvider { - private final PasswordEncoder passwordEncoder; - private final TokenProvider tokenProvider; private final SignUpTokenProvider signUpTokenProvider; private final SiteUserRepository siteUserRepository; + private final PasswordTemporaryStorage passwordTemporaryStorage; + @Transactional(readOnly = true) public String issueEmailSignUpToken(EmailSignUpTokenRequest request) { String email = request.email(); + String password = request.password(); + if (siteUserRepository.existsByEmailAndAuthType(email, AuthType.EMAIL)) { throw new CustomException(ErrorCode.USER_ALREADY_EXISTED); } - String signUpToken = signUpTokenProvider.generateAndSaveSignUpToken(email, AuthType.EMAIL); - String password = request.password(); - String encodedPassword = passwordEncoder.encode(password); - // todo: 비밀번호 임시 저장 로직 추가 - - return tokenProvider.saveToken(signUpToken, TokenType.SIGN_UP); + passwordTemporaryStorage.save(email, password); + return signUpTokenProvider.generateAndSaveSignUpToken(email, AuthType.EMAIL); } - public String getTemporarySavedPassword(String signUpToken) { - // todo: 임시 저장된 비밀번호를 가져오는 로직 추가 - return ""; + public String getTemporarySavedPassword(String email) { + return passwordTemporaryStorage.findByEmail(email) // 임시 저장된 비밀번호가 없다면 signUpToken에 문제가 있는 것 + .orElseThrow(() -> new CustomException(ErrorCode.SIGN_UP_TOKEN_INVALID)); } } diff --git a/src/main/java/com/example/solidconnection/auth/service/PasswordTemporaryStorage.java b/src/main/java/com/example/solidconnection/auth/service/PasswordTemporaryStorage.java new file mode 100644 index 000000000..297c7021f --- /dev/null +++ b/src/main/java/com/example/solidconnection/auth/service/PasswordTemporaryStorage.java @@ -0,0 +1,41 @@ +package com.example.solidconnection.auth.service; + +import com.example.solidconnection.auth.domain.TokenType; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class PasswordTemporaryStorage { + + private static final String KEY_PREFIX = "password:"; + + private final RedisTemplate redisTemplate; + private final PasswordEncoder passwordEncoder; + + public void save(String email, String rawPassword) { + String encodedPassword = passwordEncoder.encode(rawPassword); + redisTemplate.opsForValue().set( + convertToKey(email), + encodedPassword, + TokenType.SIGN_UP.getExpireTime(), + TimeUnit.MILLISECONDS + ); + } + + public Optional findByEmail(String email) { + String encodedPassword = redisTemplate.opsForValue().getAndDelete(convertToKey(email)); + if (encodedPassword == null) { + return Optional.empty(); + } + return Optional.of(encodedPassword); + } + + private String convertToKey(String email) { + return KEY_PREFIX + email; + } +} From debdd25c0d42ffc7c26bc41990df7817604a8dcd Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 03:16:39 +0900 Subject: [PATCH 08/15] =?UTF-8?q?test:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=9E=84=EC=8B=9C=20=EC=A0=80=EC=9E=A5=EC=86=8C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/PasswordTemporaryStorageTest.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/test/java/com/example/solidconnection/auth/service/PasswordTemporaryStorageTest.java diff --git a/src/test/java/com/example/solidconnection/auth/service/PasswordTemporaryStorageTest.java b/src/test/java/com/example/solidconnection/auth/service/PasswordTemporaryStorageTest.java new file mode 100644 index 000000000..65b9ce0ec --- /dev/null +++ b/src/test/java/com/example/solidconnection/auth/service/PasswordTemporaryStorageTest.java @@ -0,0 +1,52 @@ +package com.example.solidconnection.auth.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.example.solidconnection.support.TestContainerSpringBootTest; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; + +@DisplayName("비밀번호 임시 저장소 테스트") +@TestContainerSpringBootTest +class PasswordTemporaryStorageTest { + + @Autowired + private PasswordTemporaryStorage passwordTemporaryStorage; + + @Autowired + private PasswordEncoder passwordEncoder; + + private final String email = "test@email.com"; + private final String rawPassword = "password123"; + + @Test + void 인코딩된_비밀번호를_임시_저장소에_저장하고_조회한다() { + // when + passwordTemporaryStorage.save(email, rawPassword); + Optional foundPassword = passwordTemporaryStorage.findByEmail(email); + + // then + assertThat(foundPassword).isPresent(); + assertThat(passwordEncoder.matches(rawPassword, foundPassword.get())).isTrue(); + } + + @Test + void 비밀번호는_한_번_조회된_후_삭제된다() { + // given + passwordTemporaryStorage.save(email, rawPassword); + + // when + Optional foundPassword1 = passwordTemporaryStorage.findByEmail(email); + Optional foundPassword2 = passwordTemporaryStorage.findByEmail(email); + + // then + assertAll( + () -> assertThat(foundPassword1).isPresent(), + () -> assertThat(foundPassword2).isEmpty() + ); + } +} From 77b3d4f2101a414eee601f05548599eff218c7bd Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 12 Aug 2025 03:23:42 +0900 Subject: [PATCH 09/15] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=BD=94=EB=93=9C=20=EA=B0=80?= =?UTF-8?q?=EB=8F=85=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/EmailSignInService.java | 25 +++++++++---------- .../common/exception/ErrorCode.java | 1 + .../auth/service/EmailSignInServiceTest.java | 4 +-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignInService.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignInService.java index d7ee365d8..4dac56586 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignInService.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignInService.java @@ -1,6 +1,6 @@ package com.example.solidconnection.auth.service; -import static com.example.solidconnection.common.exception.ErrorCode.USER_NOT_FOUND; +import static com.example.solidconnection.common.exception.ErrorCode.SIGN_IN_FAILED; import com.example.solidconnection.auth.dto.EmailSignInRequest; import com.example.solidconnection.auth.dto.SignInResponse; @@ -8,14 +8,11 @@ import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; -import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; -/* - * 보안을 위해 이메일과 비밀번호 중 무엇이 틀렸는지 구체적으로 응답하지 않는다. - * */ @Service @RequiredArgsConstructor public class EmailSignInService { @@ -24,19 +21,21 @@ public class EmailSignInService { private final SiteUserRepository siteUserRepository; private final PasswordEncoder passwordEncoder; + @Transactional(readOnly = true) public SignInResponse signIn(EmailSignInRequest signInRequest) { - Optional optionalSiteUser = siteUserRepository.findByEmailAndAuthType(signInRequest.email(), AuthType.EMAIL); - if (optionalSiteUser.isPresent()) { - SiteUser siteUser = optionalSiteUser.get(); - validatePassword(signInRequest.password(), siteUser.getPassword()); - return signInService.signIn(siteUser); - } - throw new CustomException(USER_NOT_FOUND, "이메일과 비밀번호를 확인해주세요."); + SiteUser siteUser = getEmailMatchingUserOrThrow(signInRequest.email()); + validatePassword(signInRequest.password(), siteUser.getPassword()); + return signInService.signIn(siteUser); + } + + private SiteUser getEmailMatchingUserOrThrow(String email) { + return siteUserRepository.findByEmailAndAuthType(email, AuthType.EMAIL) + .orElseThrow(() -> new CustomException(SIGN_IN_FAILED)); } private void validatePassword(String rawPassword, String encodedPassword) { if (!passwordEncoder.matches(rawPassword, encodedPassword)) { - throw new CustomException(USER_NOT_FOUND, "이메일과 비밀번호를 확인해주세요."); + throw new CustomException(SIGN_IN_FAILED); } } } diff --git a/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java b/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java index b0b04829b..80b833a9c 100644 --- a/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java @@ -56,6 +56,7 @@ public enum ErrorCode { ACCESS_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED.value(), "액세스 토큰이 만료되었습니다. 재발급 api를 호출해주세요."), REFRESH_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED.value(), "리프레시 토큰이 만료되었습니다. 다시 로그인을 진행해주세요."), ACCESS_DENIED(HttpStatus.FORBIDDEN.value(), "접근 권한이 없습니다."), + SIGN_IN_FAILED(HttpStatus.UNAUTHORIZED.value(), "로그인에 실패했습니다. 이메일과 비밀번호를 확인해주세요."), // s3 S3_SERVICE_EXCEPTION(HttpStatus.BAD_REQUEST.value(), "S3 서비스 에러 발생"), diff --git a/src/test/java/com/example/solidconnection/auth/service/EmailSignInServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/EmailSignInServiceTest.java index f9d481311..04b6780ad 100644 --- a/src/test/java/com/example/solidconnection/auth/service/EmailSignInServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/EmailSignInServiceTest.java @@ -55,7 +55,7 @@ class 로그인에_실패한다 { // when & then assertThatCode(() -> emailSignInService.signIn(signInRequest)) .isInstanceOf(CustomException.class) - .hasMessageContaining(ErrorCode.USER_NOT_FOUND.getMessage()); + .hasMessageContaining(ErrorCode.SIGN_IN_FAILED.getMessage()); } @Test @@ -68,7 +68,7 @@ class 로그인에_실패한다 { // when & then assertThatCode(() -> emailSignInService.signIn(signInRequest)) .isInstanceOf(CustomException.class) - .hasMessageContaining(ErrorCode.USER_NOT_FOUND.getMessage()); + .hasMessageContaining(ErrorCode.SIGN_IN_FAILED.getMessage()); } } } From d37fb7d5bace08794ae22608182dcde585dfcebc Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 13 Aug 2025 02:29:36 +0900 Subject: [PATCH 10/15] =?UTF-8?q?refactor:=20transactional=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../location/country/service/InterestedCountryService.java | 2 ++ .../location/region/service/InterestedRegionService.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java b/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java index 1fca11b5d..8166de968 100644 --- a/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java +++ b/src/main/java/com/example/solidconnection/location/country/service/InterestedCountryService.java @@ -7,6 +7,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -15,6 +16,7 @@ public class InterestedCountryService { private final CountryRepository countryRepository; private final InterestedCountryRepository interestedCountryRepository; + @Transactional public void saveInterestedCountry(SiteUser siteUser, List koreanNames) { List interestedCountries = countryRepository.findAllByKoreanNameIn(koreanNames) .stream() diff --git a/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java b/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java index 2a6ae3c6e..6dc71263e 100644 --- a/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java +++ b/src/main/java/com/example/solidconnection/location/region/service/InterestedRegionService.java @@ -7,6 +7,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -15,6 +16,7 @@ public class InterestedRegionService { private final RegionRepository regionRepository; private final InterestedRegionRepository interestedRegionRepository; + @Transactional public void saveInterestedRegion(SiteUser siteUser, List koreanNames) { List interestedRegions = regionRepository.findAllByKoreanNameIn(koreanNames) .stream() From c93a8838f25fbf0ba048d0f6f53f0fdb147881a7 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 13 Aug 2025 05:34:59 +0900 Subject: [PATCH 11/15] =?UTF-8?q?refactor:=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - '회원가입' 서비스에 있는게 더 적절할 것이라 판단 --- .../auth/service/EmailSignUpTokenProvider.java | 5 ----- .../example/solidconnection/auth/service/SignUpService.java | 5 ++++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java index 91d30f164..a3e2e5dc9 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java @@ -29,9 +29,4 @@ public String issueEmailSignUpToken(EmailSignUpTokenRequest request) { passwordTemporaryStorage.save(email, password); return signUpTokenProvider.generateAndSaveSignUpToken(email, AuthType.EMAIL); } - - public String getTemporarySavedPassword(String email) { - return passwordTemporaryStorage.findByEmail(email) // 임시 저장된 비밀번호가 없다면 signUpToken에 문제가 있는 것 - .orElseThrow(() -> new CustomException(ErrorCode.SIGN_UP_TOKEN_INVALID)); - } } diff --git a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java index 0e0d0f876..a9eaa5134 100644 --- a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java @@ -1,6 +1,7 @@ package com.example.solidconnection.auth.service; import static com.example.solidconnection.common.exception.ErrorCode.NICKNAME_ALREADY_EXISTED; +import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_INVALID; import static com.example.solidconnection.common.exception.ErrorCode.USER_ALREADY_EXISTED; import com.example.solidconnection.auth.dto.SignInResponse; @@ -33,6 +34,7 @@ public class SignUpService { private final InterestedCountryService interestedCountryService; private final EmailSignUpTokenProvider emailSignUpTokenProvider; private final SignUpTokenProvider signUpTokenProvider; + private final PasswordTemporaryStorage passwordTemporaryStorage; @Transactional public SignInResponse signUp(SignUpRequest signUpRequest) { @@ -79,7 +81,8 @@ private void validateUserNotDuplicated(String email, AuthType authType) { private String getTemporarySavedPassword(String email, AuthType authType) { if (authType == AuthType.EMAIL) { - return emailSignUpTokenProvider.getTemporarySavedPassword(email); + return passwordTemporaryStorage.findByEmail(email) + .orElseThrow(() -> new CustomException(SIGN_UP_TOKEN_INVALID)); } return null; } From e9a79df05e5e92819a71ef272fda801cea9c6da4 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 13 Aug 2025 05:38:28 +0900 Subject: [PATCH 12/15] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=EC=97=90=20=EC=82=AC=EC=9A=A9=EB=90=9C=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/PasswordTemporaryStorage.java | 7 ++++++- .../auth/service/SignUpService.java | 14 +++++++++++++- .../auth/service/SignUpTokenProvider.java | 5 +++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/PasswordTemporaryStorage.java b/src/main/java/com/example/solidconnection/auth/service/PasswordTemporaryStorage.java index 297c7021f..adcb8bf68 100644 --- a/src/main/java/com/example/solidconnection/auth/service/PasswordTemporaryStorage.java +++ b/src/main/java/com/example/solidconnection/auth/service/PasswordTemporaryStorage.java @@ -28,13 +28,18 @@ public void save(String email, String rawPassword) { } public Optional findByEmail(String email) { - String encodedPassword = redisTemplate.opsForValue().getAndDelete(convertToKey(email)); + String encodedPassword = redisTemplate.opsForValue().get(convertToKey(email)); if (encodedPassword == null) { return Optional.empty(); } return Optional.of(encodedPassword); } + public void deleteByEmail(String email) { + String key = convertToKey(email); + redisTemplate.delete(key); + } + private String convertToKey(String email) { return KEY_PREFIX + email; } diff --git a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java index a9eaa5134..86d93db15 100644 --- a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java @@ -64,7 +64,12 @@ public SignInResponse signUp(SignUpRequest signUpRequest) { interestedCountryService.saveInterestedCountry(siteUser, signUpRequest.interestedCountries()); // 로그인 - return signInService.signIn(siteUser); + SignInResponse response = signInService.signIn(siteUser); + + // 회원가입을 위해 저장한 데이터(SignUpToken, 비밀번호) 삭제 + clearSignUpData(email, authType); + + return response; } private void validateNicknameNotDuplicated(String nickname) { @@ -86,4 +91,11 @@ private String getTemporarySavedPassword(String email, AuthType authType) { } return null; } + + private void clearSignUpData(String email, AuthType authType) { + if (authType == AuthType.EMAIL) { + passwordTemporaryStorage.deleteByEmail(email); + } + signUpTokenProvider.deleteByEmail(email); + } } diff --git a/src/main/java/com/example/solidconnection/auth/service/SignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/SignUpTokenProvider.java index a8ecd574b..05480b10d 100644 --- a/src/main/java/com/example/solidconnection/auth/service/SignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/SignUpTokenProvider.java @@ -43,6 +43,11 @@ public String generateAndSaveSignUpToken(String email, AuthType authType) { return tokenProvider.saveToken(signUpToken, TokenType.SIGN_UP); } + public void deleteByEmail(String email) { + String key = TokenType.SIGN_UP.addPrefix(email); + redisTemplate.delete(key); + } + public void validateSignUpToken(String token) { validateFormatAndExpiration(token); String email = parseEmail(token); From 34197d73311e17df0b07c0c6eeccc5271b7a65f3 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 13 Aug 2025 05:55:38 +0900 Subject: [PATCH 13/15] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=86=A0=ED=81=B0,=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=EB=90=9C=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=82=AD=EC=A0=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/PasswordTemporaryStorageTest.java | 12 ++++-------- .../auth/service/SignUpTokenProviderTest.java | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/example/solidconnection/auth/service/PasswordTemporaryStorageTest.java b/src/test/java/com/example/solidconnection/auth/service/PasswordTemporaryStorageTest.java index 65b9ce0ec..ea3ed6355 100644 --- a/src/test/java/com/example/solidconnection/auth/service/PasswordTemporaryStorageTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/PasswordTemporaryStorageTest.java @@ -1,7 +1,6 @@ package com.example.solidconnection.auth.service; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; import com.example.solidconnection.support.TestContainerSpringBootTest; import java.util.Optional; @@ -35,18 +34,15 @@ class PasswordTemporaryStorageTest { } @Test - void 비밀번호는_한_번_조회된_후_삭제된다() { + void 임시_저장된_비밀번호를_삭제한다() { // given passwordTemporaryStorage.save(email, rawPassword); // when - Optional foundPassword1 = passwordTemporaryStorage.findByEmail(email); - Optional foundPassword2 = passwordTemporaryStorage.findByEmail(email); + passwordTemporaryStorage.deleteByEmail(email); + Optional foundPassword = passwordTemporaryStorage.findByEmail(email); // then - assertAll( - () -> assertThat(foundPassword1).isPresent(), - () -> assertThat(foundPassword2).isEmpty() - ); + assertThat(foundPassword).isEmpty(); } } diff --git a/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java index 1793bb6cc..de8a5df63 100644 --- a/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java @@ -63,6 +63,21 @@ class SignUpTokenProviderTest { ); } + @Test + void 회원가입_토큰을_삭제한다() { + // given + String email = "email"; + AuthType authType = AuthType.KAKAO; + signUpTokenProvider.generateAndSaveSignUpToken(email, authType); + + // when + signUpTokenProvider.deleteByEmail(email); + + // then + String signUpTokenKey = TokenType.SIGN_UP.addPrefix(email); + assertThat(redisTemplate.opsForValue().get(signUpTokenKey)).isNull(); + } + @Nested class 주어진_회원가입_토큰을_검증한다 { From 828d8a2fd614489bc455234a1b53a81c6e8c5e7d Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 13 Aug 2025 06:15:30 +0900 Subject: [PATCH 14/15] =?UTF-8?q?test:=20=EB=B0=A9=EB=B3=B5=ED=95=B4?= =?UTF-8?q?=EC=84=9C=20=EC=84=A0=EC=96=B8=EB=90=98=EB=8A=94=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/SignUpTokenProviderTest.java | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java index de8a5df63..c75eac5f5 100644 --- a/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/SignUpTokenProviderTest.java @@ -41,13 +41,11 @@ class SignUpTokenProviderTest { private JwtProperties jwtProperties; private final String authTypeClaimKey = "authType"; + private final String email = "test@email.com"; + private final AuthType authType = AuthType.KAKAO; @Test void 회원가입_토큰을_생성하고_저장한다() { - // given - String email = "email"; - AuthType authType = AuthType.KAKAO; - // when String signUpToken = signUpTokenProvider.generateAndSaveSignUpToken(email, authType); @@ -66,8 +64,6 @@ class SignUpTokenProviderTest { @Test void 회원가입_토큰을_삭제한다() { // given - String email = "email"; - AuthType authType = AuthType.KAKAO; signUpTokenProvider.generateAndSaveSignUpToken(email, authType); // when @@ -84,8 +80,7 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 검증_성공한다() { // given - String email = "email@test.com"; - Map claim = new HashMap<>(Map.of(authTypeClaimKey, AuthType.APPLE)); + Map claim = new HashMap<>(Map.of(authTypeClaimKey, authType)); String validToken = createBaseJwtBuilder().setSubject(email).addClaims(claim).compact(); redisTemplate.opsForValue().set(TokenType.SIGN_UP.addPrefix(email), validToken); @@ -118,11 +113,12 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 정해진_형식에_맞지_않으면_예외가_발생한다_authType_클래스_불일치() { // given - Map wrongClaim = new HashMap<>(Map.of(authTypeClaimKey, "카카오")); - String wrongAuthType = createBaseJwtBuilder().addClaims(wrongClaim).compact(); + String wrongAuthType = "카카오"; + Map wrongClaim = new HashMap<>(Map.of(authTypeClaimKey, wrongAuthType)); + String wrongAuthTypeClaim = createBaseJwtBuilder().addClaims(wrongClaim).compact(); // when & then - assertThatCode(() -> signUpTokenProvider.validateSignUpToken(wrongAuthType)) + assertThatCode(() -> signUpTokenProvider.validateSignUpToken(wrongAuthTypeClaim)) .isInstanceOf(CustomException.class) .hasMessageContaining(SIGN_UP_TOKEN_INVALID.getMessage()); } @@ -130,7 +126,7 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 정해진_형식에_맞지_않으면_예외가_발생한다_subject_누락() { // given - Map claim = new HashMap<>(Map.of(authTypeClaimKey, AuthType.APPLE)); + Map claim = new HashMap<>(Map.of(authTypeClaimKey, authType)); String noSubject = createBaseJwtBuilder().addClaims(claim).compact(); // when & then @@ -142,8 +138,8 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 우리_서버에_발급된_토큰이_아니면_예외가_발생한다() { // given - Map validClaim = new HashMap<>(Map.of(authTypeClaimKey, AuthType.APPLE)); - String signUpToken = createBaseJwtBuilder().addClaims(validClaim).setSubject("email").compact(); + Map validClaim = new HashMap<>(Map.of(authTypeClaimKey, authType)); + String signUpToken = createBaseJwtBuilder().addClaims(validClaim).setSubject(email).compact(); // when & then assertThatCode(() -> signUpTokenProvider.validateSignUpToken(signUpToken)) @@ -155,8 +151,7 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 회원가입_토큰에서_이메일을_추출한다() { // given - String email = "email@test.com"; - Map claim = Map.of(authTypeClaimKey, AuthType.APPLE); + Map claim = Map.of(authTypeClaimKey, authType); String validToken = createBaseJwtBuilder().setSubject(email).addClaims(claim).compact(); redisTemplate.opsForValue().set(TokenType.SIGN_UP.addPrefix(email), validToken); @@ -170,9 +165,8 @@ class 주어진_회원가입_토큰을_검증한다 { @Test void 회원가입_토큰에서_인증_타입을_추출한다() { // given - AuthType authType = AuthType.APPLE; Map claim = Map.of(authTypeClaimKey, authType); - String validToken = createBaseJwtBuilder().setSubject("email").addClaims(claim).compact(); + String validToken = createBaseJwtBuilder().setSubject(email).addClaims(claim).compact(); // when AuthType extractedAuthType = signUpTokenProvider.parseAuthType(validToken); @@ -183,7 +177,7 @@ class 주어진_회원가입_토큰을_검증한다 { private String createExpiredToken() { return Jwts.builder() - .setSubject("subject") + .setSubject(email) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() - 1000)) .signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) From a6a57b90d602fb64f2c2b28afd5e91ae3dbe7643 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 13 Aug 2025 06:51:36 +0900 Subject: [PATCH 15/15] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/solidconnection/auth/service/SignUpService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java index 86d93db15..d6feed9e1 100644 --- a/src/main/java/com/example/solidconnection/auth/service/SignUpService.java +++ b/src/main/java/com/example/solidconnection/auth/service/SignUpService.java @@ -32,7 +32,6 @@ public class SignUpService { private final SiteUserRepository siteUserRepository; private final InterestedRegionService interestedRegionService; private final InterestedCountryService interestedCountryService; - private final EmailSignUpTokenProvider emailSignUpTokenProvider; private final SignUpTokenProvider signUpTokenProvider; private final PasswordTemporaryStorage passwordTemporaryStorage;