diff --git a/src/main/java/com/kcy/fitapet/domain/member/api/AccountApi.java b/src/main/java/com/kcy/fitapet/domain/member/api/AccountApi.java index e36b8bc2..85a3cb28 100644 --- a/src/main/java/com/kcy/fitapet/domain/member/api/AccountApi.java +++ b/src/main/java/com/kcy/fitapet/domain/member/api/AccountApi.java @@ -4,16 +4,12 @@ import com.kcy.fitapet.domain.member.dto.account.AccountSearchReq; import com.kcy.fitapet.domain.member.dto.account.ProfilePatchReq; import com.kcy.fitapet.domain.member.dto.account.UidRes; -import com.kcy.fitapet.domain.member.exception.AccountErrorCode; import com.kcy.fitapet.domain.member.service.component.MemberAccountService; import com.kcy.fitapet.domain.member.type.MemberAttrType; import com.kcy.fitapet.domain.notification.type.NotificationType; import com.kcy.fitapet.global.common.response.SuccessResponse; -import com.kcy.fitapet.global.common.response.code.ErrorCode; -import com.kcy.fitapet.global.common.response.code.StatusCode; -import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; import com.kcy.fitapet.global.common.security.authentication.CustomUserDetails; -import com.kcy.fitapet.global.common.redis.sms.SmsPrefix; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; @@ -22,7 +18,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/com/kcy/fitapet/domain/member/api/AuthApi.java b/src/main/java/com/kcy/fitapet/domain/member/api/AuthApi.java index bfd5e706..9e6ff960 100644 --- a/src/main/java/com/kcy/fitapet/domain/member/api/AuthApi.java +++ b/src/main/java/com/kcy/fitapet/domain/member/api/AuthApi.java @@ -2,7 +2,7 @@ import com.kcy.fitapet.domain.member.dto.auth.SignInReq; import com.kcy.fitapet.domain.member.dto.auth.SignUpReq; -import com.kcy.fitapet.global.common.redis.sms.SmsPrefix; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; import com.kcy.fitapet.global.common.util.sms.dto.SmsReq; import com.kcy.fitapet.global.common.util.sms.dto.SmsRes; import com.kcy.fitapet.domain.member.exception.SmsErrorCode; diff --git a/src/main/java/com/kcy/fitapet/domain/member/service/component/MemberAccountService.java b/src/main/java/com/kcy/fitapet/domain/member/service/component/MemberAccountService.java index 8c5731fb..99debbc4 100644 --- a/src/main/java/com/kcy/fitapet/domain/member/service/component/MemberAccountService.java +++ b/src/main/java/com/kcy/fitapet/domain/member/service/component/MemberAccountService.java @@ -10,8 +10,8 @@ import com.kcy.fitapet.domain.member.service.module.MemberSearchService; import com.kcy.fitapet.domain.member.type.MemberAttrType; import com.kcy.fitapet.domain.notification.type.NotificationType; -import com.kcy.fitapet.global.common.redis.sms.SmsCertificationService; -import com.kcy.fitapet.global.common.redis.sms.SmsPrefix; +import com.kcy.fitapet.global.common.redis.sms.provider.SmsRedisProvider; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; import com.kcy.fitapet.global.common.response.code.StatusCode; import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; import lombok.RequiredArgsConstructor; @@ -26,7 +26,7 @@ @Slf4j public class MemberAccountService { private final MemberSearchService memberSearchService; - private final SmsCertificationService smsCertificationService; + private final SmsRedisProvider smsRedisProvider; private final PasswordEncoder bCryptPasswordEncoder; @@ -125,13 +125,13 @@ private void validatePassword(Member member, String prePassword, String newPassw * @param prefix : 인증번호 타입 */ private void validatePhone(String phone, String code, SmsPrefix prefix) { - if (!smsCertificationService.existsCode(phone, prefix)) { + if (!smsRedisProvider.isExistsCode(phone, prefix)) { StatusCode errorCode = SmsErrorCode.EXPIRED_AUTH_CODE; log.warn("인증번호 유효성 검사 실패: {}", errorCode); throw new GlobalErrorException(errorCode); } - if (!smsCertificationService.isCorrectCode(phone, code, prefix)) { + if (!smsRedisProvider.isCorrectCode(phone, code, prefix)) { StatusCode errorCode = SmsErrorCode.INVALID_AUTH_CODE; log.warn("인증번호 유효성 검사 실패: {}", errorCode); throw new GlobalErrorException(errorCode); diff --git a/src/main/java/com/kcy/fitapet/domain/member/service/component/MemberAuthService.java b/src/main/java/com/kcy/fitapet/domain/member/service/component/MemberAuthService.java index 51a62de3..a20f6267 100644 --- a/src/main/java/com/kcy/fitapet/domain/member/service/component/MemberAuthService.java +++ b/src/main/java/com/kcy/fitapet/domain/member/service/component/MemberAuthService.java @@ -16,8 +16,8 @@ import com.kcy.fitapet.global.common.redis.forbidden.ForbiddenTokenService; import com.kcy.fitapet.global.common.redis.refresh.RefreshToken; import com.kcy.fitapet.global.common.redis.refresh.RefreshTokenService; -import com.kcy.fitapet.global.common.redis.sms.SmsCertificationService; -import com.kcy.fitapet.global.common.redis.sms.SmsPrefix; +import com.kcy.fitapet.global.common.redis.sms.provider.SmsRedisProvider; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; import com.kcy.fitapet.global.common.util.sms.SmsProvider; import com.kcy.fitapet.global.common.util.sms.dto.SensInfo; import com.kcy.fitapet.global.common.util.sms.dto.SmsReq; @@ -44,7 +44,7 @@ public class MemberAuthService { private final RefreshTokenService refreshTokenService; private final ForbiddenTokenService forbiddenTokenService; - private final SmsCertificationService smsCertificationService; + private final SmsRedisProvider smsRedisProvider; private final SmsProvider smsProvider; private final JwtUtil jwtUtil; @@ -56,7 +56,7 @@ public Map register(String requestAccessToken, SignUpReq dto) { String accessToken = jwtUtil.resolveToken(requestAccessToken); String authenticatedPhone = jwtUtil.getPhoneNumberFromToken(accessToken); - smsCertificationService.removeCode(authenticatedPhone, SmsPrefix.REGISTER); + smsRedisProvider.removeCode(authenticatedPhone, SmsPrefix.REGISTER); Member requestMember = dto.toEntity(authenticatedPhone); requestMember.encodePassword(bCryptPasswordEncoder); @@ -100,34 +100,34 @@ public SmsRes sendCode(SmsReq dto, SmsPrefix prefix) { validateForSms(prefix, dto); SensInfo smsInfo = smsProvider.sendCodeByPhoneNumber(dto); - smsCertificationService.saveSmsAuthToken(dto.to(), smsInfo.code(), prefix); - LocalDateTime expireTime = smsCertificationService.getExpiredTime(dto.to(), prefix); + smsRedisProvider.saveSmsAuthToken(dto.to(), smsInfo.code(), prefix); + LocalDateTime expireTime = smsRedisProvider.getExpiredTime(dto.to(), prefix); log.info("인증번호 만료 시간: {}", expireTime); return SmsRes.of(dto.to(), smsInfo.requestTime(), expireTime); } @Transactional public String checkCodeForRegister(SmsReq smsReq, String requestCode) { - if (!smsCertificationService.isCorrectCode(smsReq.to(), requestCode, SmsPrefix.REGISTER)) { + if (!smsRedisProvider.isCorrectCode(smsReq.to(), requestCode, SmsPrefix.REGISTER)) { log.warn("인증번호 불일치 -> 사용자 입력 인증 번호 : {}", requestCode); throw new GlobalErrorException(SmsErrorCode.INVALID_AUTH_CODE); } String token = jwtUtil.generateSmsAuthToken(SmsAuthInfo.of(1L, smsReq.to())); - smsCertificationService.saveSmsAuthToken(smsReq.to(), token, SmsPrefix.REGISTER); + smsRedisProvider.saveSmsAuthToken(smsReq.to(), token, SmsPrefix.REGISTER); return token; } @Transactional(readOnly = true) public void checkCodeForSearch(SmsReq req, String code, SmsPrefix prefix) { - if (!smsCertificationService.existsCode(req.to(), prefix)) { + if (!smsRedisProvider.isExistsCode(req.to(), prefix)) { StatusCode errorCode = SmsErrorCode.EXPIRED_AUTH_CODE; log.warn("인증번호 유효성 검사 실패: {}", errorCode); throw new GlobalErrorException(errorCode); } - if (!smsCertificationService.isCorrectCode(req.to(), code, prefix)) { + if (!smsRedisProvider.isCorrectCode(req.to(), code, prefix)) { StatusCode errorCode = SmsErrorCode.INVALID_AUTH_CODE; log.warn("인증번호 유효성 검사 실패: {}", errorCode); throw new GlobalErrorException(errorCode); diff --git a/src/main/java/com/kcy/fitapet/domain/oauth/api/OauthApi.java b/src/main/java/com/kcy/fitapet/domain/oauth/api/OauthApi.java index 6e9e8afc..e0dee504 100644 --- a/src/main/java/com/kcy/fitapet/domain/oauth/api/OauthApi.java +++ b/src/main/java/com/kcy/fitapet/domain/oauth/api/OauthApi.java @@ -5,7 +5,7 @@ import com.kcy.fitapet.domain.oauth.dto.OauthSignUpReq; import com.kcy.fitapet.domain.oauth.service.component.OauthService; import com.kcy.fitapet.domain.oauth.type.ProviderType; -import com.kcy.fitapet.global.common.redis.sms.SmsPrefix; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; import com.kcy.fitapet.global.common.response.SuccessResponse; import com.kcy.fitapet.global.common.security.jwt.dto.Jwt; import com.kcy.fitapet.global.common.util.cookie.CookieUtil; diff --git a/src/main/java/com/kcy/fitapet/domain/oauth/service/component/OauthService.java b/src/main/java/com/kcy/fitapet/domain/oauth/service/component/OauthService.java index d2fd5df6..a2ae30df 100644 --- a/src/main/java/com/kcy/fitapet/domain/oauth/service/component/OauthService.java +++ b/src/main/java/com/kcy/fitapet/domain/oauth/service/component/OauthService.java @@ -13,8 +13,8 @@ import com.kcy.fitapet.domain.oauth.service.module.OauthSearchService; import com.kcy.fitapet.domain.oauth.type.ProviderType; import com.kcy.fitapet.global.common.redis.oauth.OIDCTokenService; -import com.kcy.fitapet.global.common.redis.sms.SmsCertificationService; -import com.kcy.fitapet.global.common.redis.sms.SmsPrefix; +import com.kcy.fitapet.global.common.redis.sms.provider.SmsRedisProvider; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; import com.kcy.fitapet.global.common.security.jwt.JwtUtil; import com.kcy.fitapet.global.common.security.jwt.dto.Jwt; @@ -51,7 +51,7 @@ public class OauthService { private final JwtUtil jwtUtil; private final OIDCTokenService oidcTokenService; private final SmsProvider smsProvider; - private final SmsCertificationService smsCertificationService; + private final SmsRedisProvider smsRedisProvider; @Transactional public Jwt signInByOIDC(Long id, String idToken, ProviderType provider, String nonce) { @@ -88,21 +88,21 @@ public Jwt signUpByOIDC(Long id, ProviderType provider, OauthSignUpReq req) { public SmsRes sendCode(SmsReq dto, Long id, ProviderType provider, SmsPrefix prefix) { SensInfo smsInfo = smsProvider.sendCodeByPhoneNumber(dto); - smsCertificationService.saveSmsAuthToken(dto.to(), smsInfo.code(), prefix); - LocalDateTime expireTime = smsCertificationService.getExpiredTime(dto.to(), prefix); + smsRedisProvider.saveSmsAuthToken(dto.to(), smsInfo.code(), prefix); + LocalDateTime expireTime = smsRedisProvider.getExpiredTime(dto.to(), prefix); log.info("인증번호 만료 시간: {}", expireTime); return SmsRes.of(dto.to(), smsInfo.requestTime(), expireTime); } @Transactional public String checkCertificationNumber(SmsReq req, Long id, String code) { - if (!smsCertificationService.isCorrectCode(req.to(), code, SmsPrefix.REGISTER)) { + if (!smsRedisProvider.isCorrectCode(req.to(), code, SmsPrefix.REGISTER)) { log.warn("인증번호 불일치 -> 사용자 입력 인증 번호 : {}", code); throw new GlobalErrorException(SmsErrorCode.INVALID_AUTH_CODE); } String token = jwtUtil.generateSmsOauthToken(SmsAuthInfo.of(id, req.to())); - smsCertificationService.saveSmsAuthToken(req.to(), token, SmsPrefix.OAUTH); + smsRedisProvider.saveSmsAuthToken(req.to(), token, SmsPrefix.OAUTH); return token; } diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsCertificationServiceImpl.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsCertificationServiceImpl.java deleted file mode 100644 index 13d28558..00000000 --- a/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsCertificationServiceImpl.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.kcy.fitapet.global.common.redis.sms; - -import com.kcy.fitapet.domain.member.exception.SmsErrorCode; -import com.kcy.fitapet.global.common.redis.sms.dao.*; -import com.kcy.fitapet.global.common.redis.sms.domain.*; -import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; -import java.util.Optional; - -@Slf4j -@Service -@RequiredArgsConstructor -public class SmsCertificationServiceImpl implements SmsCertificationService { - private final SmsOauthRepository smsOauthRepository; - private final SmsPasswordRepository smsPasswordRepository; - private final SmsRegisterRepository smsRegisterRepository; - private final SmsUidRepository smsUidRepository; - - private final RedisTemplate redisTemplate; - - @Override - public void saveSmsAuthToken(String phone, String code, SmsPrefix prefix) { - switch (prefix) { - case OAUTH -> smsOauthRepository.save(SmsOauth.of(phone, code)); - case PASSWORD -> smsPasswordRepository.save(SmsPassword.of(phone, code)); - case REGISTER -> smsRegisterRepository.save(SmsRegister.of(phone, code)); - case UID -> smsUidRepository.save(SmsUid.of(phone, code)); - } - } - - @Override - public boolean isCorrectCode(String phoneNumber, String code, SmsPrefix prefix) { - switch (prefix) { - case OAUTH -> { - Optional smsOauth = smsOauthRepository.findById(phoneNumber); - return smsOauth.map(oauth -> oauth.getCode().equals(code)).orElse(false); - } - case PASSWORD -> { - Optional smsPassword = smsPasswordRepository.findById(phoneNumber); - return smsPassword.map(password -> password.getCode().equals(code)).orElse(false); - } - case REGISTER -> { - Optional smsRegister = smsRegisterRepository.findById(phoneNumber); - return smsRegister.map(register -> register.getCode().equals(code)).orElse(false); - } - case UID -> { - Optional smsUid = smsUidRepository.findById(phoneNumber); - return smsUid.map(uid -> uid.getCode().equals(code)).orElse(false); - } - default -> throw new GlobalErrorException(SmsErrorCode.NOT_FOUND_SMS_PREFIX); - } - } - - @Override - public boolean existsCode(String phoneNumber, SmsPrefix prefix) { - switch (prefix) { - case OAUTH -> {return smsOauthRepository.existsById(phoneNumber);} - case PASSWORD -> {return smsPasswordRepository.existsById(phoneNumber);} - case REGISTER -> {return smsRegisterRepository.existsById(phoneNumber);} - case UID -> {return smsUidRepository.existsById(phoneNumber);} - default -> throw new GlobalErrorException(SmsErrorCode.NOT_FOUND_SMS_PREFIX); - } - } - - @Override - public void removeCode(String phoneNumber, SmsPrefix prefix) { - switch (prefix) { - case OAUTH -> {smsOauthRepository.deleteById(phoneNumber);} - case PASSWORD -> {smsPasswordRepository.deleteById(phoneNumber);} - case REGISTER -> {smsRegisterRepository.deleteById(phoneNumber);} - case UID -> {smsUidRepository.deleteById(phoneNumber);} - default -> throw new GlobalErrorException(SmsErrorCode.NOT_FOUND_SMS_PREFIX); - } - } - - @Override - public LocalDateTime getExpiredTime(String phoneNumber, SmsPrefix prefix) { - Long ttl = redisTemplate.getExpire(getKeyName(phoneNumber, prefix)); - log.info("ttl: {}", ttl); - - if (ttl == null || ttl < 0L) - throw new GlobalErrorException(SmsErrorCode.EXPIRED_AUTH_CODE); - - return LocalDateTime.now().plusSeconds(ttl); - } - - private String getKeyName(String phoneNumber, SmsPrefix prefix) { - String str = prefix.getPrefix(); - return "sms" + str.substring(0, 1).toUpperCase() - + str.substring(1) + ":" + phoneNumber; - } -} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/dao/SmsCertificationRepository.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/dao/SmsCertificationRepository.java deleted file mode 100644 index 7b963a2e..00000000 --- a/src/main/java/com/kcy/fitapet/global/common/redis/sms/dao/SmsCertificationRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.kcy.fitapet.global.common.redis.sms.dao; - -import com.kcy.fitapet.global.common.redis.sms.domain.SmsCertification; -import org.springframework.data.repository.CrudRepository; - -public interface SmsCertificationRepository extends CrudRepository { - -} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/domain/SmsCertification.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/domain/SmsCertification.java deleted file mode 100644 index 161463dc..00000000 --- a/src/main/java/com/kcy/fitapet/global/common/redis/sms/domain/SmsCertification.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.kcy.fitapet.global.common.redis.sms.domain; - -import lombok.Builder; -import lombok.Getter; -import org.springframework.data.annotation.Id; -import org.springframework.data.redis.core.RedisHash; - -@RedisHash(value = "smsCertification", timeToLive = 300) -@Getter -public class SmsCertification { - @Id - private final String phoneNumber; - private final String code; - - @Builder - public SmsCertification(String phoneNumber, String code) { - this.phoneNumber = phoneNumber; - this.code = code; - } - - public static SmsCertification of(String phoneNumber, String code) { - return SmsCertification.builder() - .phoneNumber(phoneNumber) - .code(code) - .build(); - } -} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsOauthProvider.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsOauthProvider.java new file mode 100644 index 00000000..0aefe1de --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsOauthProvider.java @@ -0,0 +1,57 @@ +package com.kcy.fitapet.global.common.redis.sms.provider; + +import com.kcy.fitapet.domain.member.exception.SmsErrorCode; +import com.kcy.fitapet.global.common.redis.sms.dao.*; +import com.kcy.fitapet.global.common.redis.sms.domain.*; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; +import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Slf4j +@Service +@Primary +@RequiredArgsConstructor +public class SmsOauthProvider implements SmsRedisProvider { + private final SmsOauthRepository smsOauthRepository; + + private final RedisTemplate redisTemplate; + + @Override + public void saveSmsAuthToken(String phone, String code, SmsPrefix prefix) { + smsOauthRepository.save(SmsOauth.of(phone, code)); + } + + @Override + public boolean isCorrectCode(String phoneNumber, String code, SmsPrefix prefix) { + Optional smsOauth = smsOauthRepository.findById(phoneNumber); + return smsOauth.map(oauth -> oauth.getCode().equals(code)).orElse(false); + } + + @Override + public boolean isExistsCode(String phoneNumber, SmsPrefix prefix) { + return smsOauthRepository.existsById(phoneNumber); + } + + @Override + public void removeCode(String phoneNumber, SmsPrefix prefix) { + smsOauthRepository.deleteById(phoneNumber); + } + + @Override + public LocalDateTime getExpiredTime(String phoneNumber, SmsPrefix prefix) { + Long ttl = redisTemplate.getExpire(getTopic(phoneNumber, prefix)); + log.info("ttl: {}", ttl); + + if (ttl == null || ttl < 0L) + throw new GlobalErrorException(SmsErrorCode.EXPIRED_AUTH_CODE); + + return LocalDateTime.now().plusSeconds(ttl); + } +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsPasswordProvider.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsPasswordProvider.java new file mode 100644 index 00000000..24995471 --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsPasswordProvider.java @@ -0,0 +1,56 @@ +package com.kcy.fitapet.global.common.redis.sms.provider; + +import com.kcy.fitapet.domain.member.exception.SmsErrorCode; +import com.kcy.fitapet.global.common.redis.sms.dao.SmsPasswordRepository; +import com.kcy.fitapet.global.common.redis.sms.domain.SmsPassword; +import com.kcy.fitapet.global.common.redis.sms.qualify.SmsPasswordQualifier; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; +import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Slf4j +@Component +@SmsPasswordQualifier +@RequiredArgsConstructor +public class SmsPasswordProvider implements SmsRedisProvider { + private final SmsPasswordRepository smsPasswordRepository; + private final RedisTemplate restTemplate; + + @Override + public void saveSmsAuthToken(String phone, String code, SmsPrefix prefix) { + smsPasswordRepository.save(SmsPassword.of(phone, code)); + } + + @Override + public boolean isCorrectCode(String phoneNumber, String code, SmsPrefix prefix) { + Optional smsPassword = smsPasswordRepository.findById(phoneNumber); + return smsPassword.map(password -> password.getCode().equals(code)).orElse(false); + } + + @Override + public boolean isExistsCode(String phoneNumber, SmsPrefix prefix) { + return smsPasswordRepository.existsById(phoneNumber); + } + + @Override + public void removeCode(String phoneNumber, SmsPrefix prefix) { + smsPasswordRepository.deleteById(phoneNumber); + } + + @Override + public LocalDateTime getExpiredTime(String phoneNumber, SmsPrefix prefix) { + Long ttl = restTemplate.getExpire(getTopic(phoneNumber, prefix)); + log.info("ttl: {}", ttl); + + if (ttl == null || ttl < 0L) + throw new GlobalErrorException(SmsErrorCode.EXPIRED_AUTH_CODE); + + return LocalDateTime.now().plusSeconds(ttl); + } +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsCertificationService.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsRedisProvider.java similarity index 71% rename from src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsCertificationService.java rename to src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsRedisProvider.java index 9c778f7f..51216ef4 100644 --- a/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsCertificationService.java +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsRedisProvider.java @@ -1,8 +1,10 @@ -package com.kcy.fitapet.global.common.redis.sms; +package com.kcy.fitapet.global.common.redis.sms.provider; + +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; import java.time.LocalDateTime; -public interface SmsCertificationService { +public interface SmsRedisProvider { /** * SMS 인증 완료 후 계정 생성을 위한 토큰 저장 * @param phone : String @@ -25,7 +27,7 @@ public interface SmsCertificationService { * @param prefix : SmsPrefix * @return boolean : 인증번호 존재 여부 */ - boolean existsCode(String phoneNumber, SmsPrefix prefix); + boolean isExistsCode(String phoneNumber, SmsPrefix prefix); /** * 인증번호 제거 @@ -41,4 +43,10 @@ public interface SmsCertificationService { * @return LocalDateTime : 인증번호 만료 시간 */ LocalDateTime getExpiredTime(String phoneNumber, SmsPrefix prefix); + + default String getTopic(String phoneNumber, SmsPrefix prefix) { + String str = prefix.getTopic(phoneNumber); + return "sms" + str.substring(0, 1).toUpperCase() + str.substring(1) + + ":" + phoneNumber; + } } diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsRegisterProvider.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsRegisterProvider.java new file mode 100644 index 00000000..480a5c22 --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsRegisterProvider.java @@ -0,0 +1,56 @@ +package com.kcy.fitapet.global.common.redis.sms.provider; + +import com.kcy.fitapet.domain.member.exception.SmsErrorCode; +import com.kcy.fitapet.global.common.redis.sms.dao.SmsRegisterRepository; +import com.kcy.fitapet.global.common.redis.sms.domain.SmsRegister; +import com.kcy.fitapet.global.common.redis.sms.qualify.SmsRegisterQualifier; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; +import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Slf4j +@Service +@SmsRegisterQualifier +@RequiredArgsConstructor +public class SmsRegisterProvider implements SmsRedisProvider { + private final SmsRegisterRepository smsRegisterRepository; + private final RedisTemplate redisTemplate; + + @Override + public void saveSmsAuthToken(String phone, String code, SmsPrefix prefix) { + smsRegisterRepository.save(SmsRegister.of(phone, code)); + } + + @Override + public boolean isCorrectCode(String phoneNumber, String code, SmsPrefix prefix) { + Optional smsRegister = smsRegisterRepository.findById(phoneNumber); + return smsRegister.map(register -> register.getCode().equals(code)).orElse(false); + } + + @Override + public boolean isExistsCode(String phoneNumber, SmsPrefix prefix) { + return smsRegisterRepository.existsById(phoneNumber); + } + + @Override + public void removeCode(String phoneNumber, SmsPrefix prefix) { + smsRegisterRepository.deleteById(phoneNumber); + } + + @Override + public LocalDateTime getExpiredTime(String phoneNumber, SmsPrefix prefix) { + Long ttl = redisTemplate.getExpire(getTopic(phoneNumber, prefix)); + log.info("ttl: {}", ttl); + + if (ttl == null || ttl < 0L) + throw new GlobalErrorException(SmsErrorCode.EXPIRED_AUTH_CODE); + + return LocalDateTime.now().plusSeconds(ttl); + } +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsUidProvider.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsUidProvider.java new file mode 100644 index 00000000..4885debc --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/provider/SmsUidProvider.java @@ -0,0 +1,56 @@ +package com.kcy.fitapet.global.common.redis.sms.provider; + +import com.kcy.fitapet.domain.member.exception.SmsErrorCode; +import com.kcy.fitapet.global.common.redis.sms.dao.SmsUidRepository; +import com.kcy.fitapet.global.common.redis.sms.domain.SmsUid; +import com.kcy.fitapet.global.common.redis.sms.qualify.SmsUidQualifier; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; +import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Slf4j +@Service +@SmsUidQualifier +@RequiredArgsConstructor +public class SmsUidProvider implements SmsRedisProvider { + private final SmsUidRepository smsUidRepository; + private final RedisTemplate redisTemplate; + + @Override + public void saveSmsAuthToken(String phone, String code, SmsPrefix prefix) { + smsUidRepository.save(SmsUid.of(phone, code)); + } + + @Override + public boolean isCorrectCode(String phoneNumber, String code, SmsPrefix prefix) { + Optional smsUid = smsUidRepository.findById(phoneNumber); + return smsUid.map(uid -> uid.getCode().equals(code)).orElse(false); + } + + @Override + public boolean isExistsCode(String phoneNumber, SmsPrefix prefix) { + return smsUidRepository.existsById(phoneNumber); + } + + @Override + public void removeCode(String phoneNumber, SmsPrefix prefix) { + smsUidRepository.deleteById(phoneNumber); + } + + @Override + public LocalDateTime getExpiredTime(String phoneNumber, SmsPrefix prefix) { + Long ttl = redisTemplate.getExpire(getTopic(phoneNumber, prefix)); + log.info("ttl: {}", ttl); + + if (ttl == null || ttl < 0L) + throw new GlobalErrorException(SmsErrorCode.EXPIRED_AUTH_CODE); + + return LocalDateTime.now().plusSeconds(ttl); + } +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsPasswordQualifier.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsPasswordQualifier.java new file mode 100644 index 00000000..5131d361 --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsPasswordQualifier.java @@ -0,0 +1,13 @@ +package com.kcy.fitapet.global.common.redis.sms.qualify; + +import org.springframework.beans.factory.annotation.Qualifier; + +import java.lang.annotation.*; + +@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, + ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Qualifier("smsPassword") +public @interface SmsPasswordQualifier { +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsRegisterQualifier.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsRegisterQualifier.java new file mode 100644 index 00000000..5ec1b720 --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsRegisterQualifier.java @@ -0,0 +1,13 @@ +package com.kcy.fitapet.global.common.redis.sms.qualify; + +import org.springframework.beans.factory.annotation.Qualifier; + +import java.lang.annotation.*; + +@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, + ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Qualifier("smsRegister") +public @interface SmsRegisterQualifier { +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsUidQualifier.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsUidQualifier.java new file mode 100644 index 00000000..d73166b4 --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/qualify/SmsUidQualifier.java @@ -0,0 +1,13 @@ +package com.kcy.fitapet.global.common.redis.sms.qualify; + +import org.springframework.beans.factory.annotation.Qualifier; + +import java.lang.annotation.*; + +@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, + ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Qualifier("smsUid") +public @interface SmsUidQualifier { +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsOauthService.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsOauthService.java new file mode 100644 index 00000000..bcc964bb --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsOauthService.java @@ -0,0 +1,30 @@ +package com.kcy.fitapet.global.common.redis.sms.service; + +import com.kcy.fitapet.global.common.redis.sms.provider.SmsRedisProvider; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; +import org.springframework.stereotype.Service; + +@Service +public class SmsOauthService { + private final SmsRedisProvider smsRedisProvider; + + public SmsOauthService(final SmsRedisProvider smsRedisProvider) { + this.smsRedisProvider = smsRedisProvider; + } + + public void save(String phone, String code, SmsPrefix prefix) { + smsRedisProvider.saveSmsAuthToken(phone, code, prefix); + } + + public boolean isCorrectCode(String phone, String code, SmsPrefix prefix) { + return smsRedisProvider.isCorrectCode(phone, code, prefix); + } + + public boolean isExistsCode(String phone, SmsPrefix prefix) { + return smsRedisProvider.isExistsCode(phone, prefix); + } + + public void removeCode(String phone, SmsPrefix prefix) { + smsRedisProvider.removeCode(phone, prefix); + } +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsPasswordService.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsPasswordService.java new file mode 100644 index 00000000..43875bad --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsPasswordService.java @@ -0,0 +1,31 @@ +package com.kcy.fitapet.global.common.redis.sms.service; + +import com.kcy.fitapet.global.common.redis.sms.provider.SmsRedisProvider; +import com.kcy.fitapet.global.common.redis.sms.qualify.SmsPasswordQualifier; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; +import org.springframework.stereotype.Service; + +@Service +public class SmsPasswordService { + private final SmsRedisProvider smsRedisProvider; + + public SmsPasswordService(@SmsPasswordQualifier final SmsRedisProvider smsRedisProvider) { + this.smsRedisProvider = smsRedisProvider; + } + + public void save(String phone, String code, SmsPrefix prefix) { + smsRedisProvider.saveSmsAuthToken(phone, code, prefix); + } + + public boolean isCorrectCode(String phone, String code, SmsPrefix prefix) { + return smsRedisProvider.isCorrectCode(phone, code, prefix); + } + + public boolean isExistsCode(String phone, SmsPrefix prefix) { + return smsRedisProvider.isExistsCode(phone, prefix); + } + + public void removeCode(String phone, SmsPrefix prefix) { + smsRedisProvider.removeCode(phone, prefix); + } +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsRegisterService.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsRegisterService.java new file mode 100644 index 00000000..945da53e --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsRegisterService.java @@ -0,0 +1,31 @@ +package com.kcy.fitapet.global.common.redis.sms.service; + +import com.kcy.fitapet.global.common.redis.sms.provider.SmsRedisProvider; +import com.kcy.fitapet.global.common.redis.sms.qualify.SmsRegisterQualifier; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; +import org.springframework.stereotype.Service; + +@Service +public class SmsRegisterService { + private final SmsRedisProvider smsRedisProvider; + + public SmsRegisterService(@SmsRegisterQualifier final SmsRedisProvider smsRedisProvider) { + this.smsRedisProvider = smsRedisProvider; + } + + public void save(String phone, String code, SmsPrefix prefix) { + smsRedisProvider.saveSmsAuthToken(phone, code, prefix); + } + + public boolean isCorrectCode(String phone, String code, SmsPrefix prefix) { + return smsRedisProvider.isCorrectCode(phone, code, prefix); + } + + public boolean isExistsCode(String phone, SmsPrefix prefix) { + return smsRedisProvider.isExistsCode(phone, prefix); + } + + public void removeCode(String phone, SmsPrefix prefix) { + smsRedisProvider.removeCode(phone, prefix); + } +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsUidService.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsUidService.java new file mode 100644 index 00000000..65d3a3d3 --- /dev/null +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/service/SmsUidService.java @@ -0,0 +1,31 @@ +package com.kcy.fitapet.global.common.redis.sms.service; + +import com.kcy.fitapet.global.common.redis.sms.provider.SmsRedisProvider; +import com.kcy.fitapet.global.common.redis.sms.qualify.SmsUidQualifier; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefix; +import org.springframework.stereotype.Service; + +@Service +public class SmsUidService { + private final SmsRedisProvider smsRedisProvider; + + public SmsUidService(@SmsUidQualifier final SmsRedisProvider smsRedisProvider) { + this.smsRedisProvider = smsRedisProvider; + } + + public void save(String phone, String code, SmsPrefix prefix) { + smsRedisProvider.saveSmsAuthToken(phone, code, prefix); + } + + public boolean isCorrectCode(String phone, String code, SmsPrefix prefix) { + return smsRedisProvider.isCorrectCode(phone, code, prefix); + } + + public boolean isExistsCode(String phone, SmsPrefix prefix) { + return smsRedisProvider.isExistsCode(phone, prefix); + } + + public void removeCode(String phone, SmsPrefix prefix) { + smsRedisProvider.removeCode(phone, prefix); + } +} diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsPrefix.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/type/SmsPrefix.java similarity index 88% rename from src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsPrefix.java rename to src/main/java/com/kcy/fitapet/global/common/redis/sms/type/SmsPrefix.java index 13372570..d7e8771c 100644 --- a/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsPrefix.java +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/type/SmsPrefix.java @@ -1,4 +1,4 @@ -package com.kcy.fitapet.global.common.redis.sms; +package com.kcy.fitapet.global.common.redis.sms.type; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsPrefixConverter.java b/src/main/java/com/kcy/fitapet/global/common/redis/sms/type/SmsPrefixConverter.java similarity index 93% rename from src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsPrefixConverter.java rename to src/main/java/com/kcy/fitapet/global/common/redis/sms/type/SmsPrefixConverter.java index c81b9d51..80118ede 100644 --- a/src/main/java/com/kcy/fitapet/global/common/redis/sms/SmsPrefixConverter.java +++ b/src/main/java/com/kcy/fitapet/global/common/redis/sms/type/SmsPrefixConverter.java @@ -1,4 +1,4 @@ -package com.kcy.fitapet.global.common.redis.sms; +package com.kcy.fitapet.global.common.redis.sms.type; import com.kcy.fitapet.global.common.response.code.ErrorCode; import com.kcy.fitapet.global.common.response.exception.GlobalErrorException; diff --git a/src/main/java/com/kcy/fitapet/global/config/RedisConfig.java b/src/main/java/com/kcy/fitapet/global/config/RedisConfig.java index b6f040ee..abfa9ce8 100644 --- a/src/main/java/com/kcy/fitapet/global/config/RedisConfig.java +++ b/src/main/java/com/kcy/fitapet/global/config/RedisConfig.java @@ -1,6 +1,5 @@ package com.kcy.fitapet.global.config; -import com.kcy.fitapet.global.common.redis.sms.domain.SmsCertification; import com.kcy.fitapet.global.config.feign.OidcCacheManager; import com.kcy.fitapet.global.config.feign.RedisCacheConnectionFactory; import org.springframework.beans.factory.annotation.Value; @@ -61,8 +60,8 @@ public RedisConnectionFactory redisConnectionFactory() { } @Bean - public RedisTemplate redisTemplate() { - RedisTemplate template = new RedisTemplate<>(); + public RedisTemplate redisTemplate() { + RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory()); template.setKeySerializer(new StringRedisSerializer()); diff --git a/src/main/java/com/kcy/fitapet/global/config/WebConfig.java b/src/main/java/com/kcy/fitapet/global/config/WebConfig.java index 4f3b12fd..3e560116 100644 --- a/src/main/java/com/kcy/fitapet/global/config/WebConfig.java +++ b/src/main/java/com/kcy/fitapet/global/config/WebConfig.java @@ -3,7 +3,7 @@ import com.kcy.fitapet.domain.member.type.converter.MemberAttrTypeConverter; import com.kcy.fitapet.domain.notification.type.converter.NotificationTypeQueryConverter; import com.kcy.fitapet.domain.oauth.type.converter.ProviderTypeQueryConverter; -import com.kcy.fitapet.global.common.redis.sms.SmsPrefixConverter; +import com.kcy.fitapet.global.common.redis.sms.type.SmsPrefixConverter; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;