하석형 하석형 06-30
250630 하석형 인증관련 예외처리 통합, coolsms 휴대폰 인증 추가
@93ee0db88ffc01354ad39d2f4feb8e4ef2d6bc02
build.gradle
--- build.gradle
+++ build.gradle
@@ -86,6 +86,8 @@
     implementation 'org.springframework.boot:spring-boot-starter-mail'
     //oauth2
     implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
+    // coolsms 문자발송용 라이브러리
+    implementation 'net.nurigo:sdk:4.2.7'
 
     testImplementation 'org.springframework.boot:spring-boot-starter-test'
     testImplementation 'org.springframework.security:spring-security-test'
src/main/java/com/takensoft/cms/loginPolicy/web/LoginPolicyController.java
--- src/main/java/com/takensoft/cms/loginPolicy/web/LoginPolicyController.java
+++ src/main/java/com/takensoft/cms/loginPolicy/web/LoginPolicyController.java
@@ -14,7 +14,6 @@
 import com.takensoft.common.util.JWTUtil;
 import com.takensoft.common.util.ResponseUtil;
 import com.takensoft.common.util.SessionUtil;
-import com.takensoft.common.verify.vo.EmailVO;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
src/main/java/com/takensoft/cms/mber/dao/AdmMbrDAO.java
--- src/main/java/com/takensoft/cms/mber/dao/AdmMbrDAO.java
+++ src/main/java/com/takensoft/cms/mber/dao/AdmMbrDAO.java
@@ -86,6 +86,14 @@
     public String lgnIdSearchByEml(AdmMbrDTO admMbrDTO);
 
     /**
+     * @param admMbrDTO - 회원 정보 관련 DTO
+     * @return String - 로그인 아이디
+     *
+     * 휴대폰번호로 아이디 찾기
+     */
+    public String lgnIdSearchByMblTelno(AdmMbrDTO admMbrDTO);
+
+    /**
      * @param admMbrDTO - 회원정보 관련 DTO
      * @return String - 회원 아이디
      *
src/main/java/com/takensoft/cms/mber/dao/MberDAO.java
--- src/main/java/com/takensoft/cms/mber/dao/MberDAO.java
+++ src/main/java/com/takensoft/cms/mber/dao/MberDAO.java
@@ -82,6 +82,17 @@
     MberVO findByEmail(HashMap<String, Object> params);
 
     /**
+     * @param params
+     *  - mbrNm: 사용자 이름
+     *  - mblTelno: 휴대폰번호 정보
+     *  - mbrId: 회원 아이디
+     * @return MberVO - 사용자 정보
+     *
+     * 휴대폰번호로 사용자 조회 (provider 무관)
+     */
+    MberVO findByMblTelno(HashMap<String, Object> params);
+
+    /**
      * @param email - 이메일
      * @param mbrType - OAuth2 회원 유형 (K, N, G, F, S)
      * @return MberVO - OAuth2 사용자 정보
src/main/java/com/takensoft/cms/mber/service/Impl/AdmMbrServiceImpl.java
--- src/main/java/com/takensoft/cms/mber/service/Impl/AdmMbrServiceImpl.java
+++ src/main/java/com/takensoft/cms/mber/service/Impl/AdmMbrServiceImpl.java
@@ -163,6 +163,14 @@
                 mbrService.findByCheckEmail(emlParams);
             }
 
+            // 휴대폰번호 중복 검사
+            if (admMbrDTO.getMblTelno() != null || !admMbrDTO.getMblTelno().isEmpty()) {
+                HashMap<String, Object> mblTelnoParams = new HashMap<>();
+                mblTelnoParams.put("mblTelno", admMbrDTO.getMblTelno());
+                mblTelnoParams.put("mbrId", admMbrDTO.getMbrId());
+                mbrService.findByCheckMblTelno(mblTelnoParams);
+            }
+
             // 비밀번호 변경
             if (admMbrDTO.getPswd() != null && !admMbrDTO.getPswd().equals("")) {
                 PasswordDTO passwordDTO = new PasswordDTO();
@@ -339,7 +347,8 @@
                 lgnId = admMbrDAO.lgnIdSearchByEml(admMbrDTO);
             } else if(admMbrDTO.getMblTelno() != null || !admMbrDTO.getMblTelno().isEmpty()) {
                 // 휴대폰 번호로 아이디 찾기
-//                lgnId = admMbrDAO.lgnIdSearchByMblTelno(mbrVO);
+                admMbrDTO.setMblTelno(Secret.encrypt(admMbrDTO.getMblTelno())); // 휴대폰 번호 암호화
+                lgnId = admMbrDAO.lgnIdSearchByMblTelno(admMbrDTO);
             }
             return lgnId;
         } catch (DataAccessException dae) {
src/main/java/com/takensoft/cms/mber/service/Impl/MberServiceImpl.java
--- src/main/java/com/takensoft/cms/mber/service/Impl/MberServiceImpl.java
+++ src/main/java/com/takensoft/cms/mber/service/Impl/MberServiceImpl.java
@@ -127,6 +127,32 @@
     }
 
     /**
+     * @param params
+     *  - mblTelno: 휴대폰번호 정보
+     *  - mbrId: 회원 아이디
+     * @return boolean - 휴대폰번호 중복 여부
+     * @throws CustomIdTakenException - 이메일 중복 예외 발생 시
+     * @throws DataAccessException - db 관련 예외 발생 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
+     * 휴대폰번호 중복 검사
+     */
+    @Override
+    public boolean findByCheckMblTelno(HashMap<String, Object> params) {
+        try {
+            MberVO existingUser = mberDAO.findByMblTelno(params);
+            if (existingUser != null) {
+                throw new CustomMblTelnoTakenException("해당 휴대폰번호로 이미 계정이 등록되어 있습니다.");
+            }
+            return true;
+        } catch (DataAccessException dae) {
+            throw dae;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
+    /**
      * @param req - HTTP 요청 객체
      * @param joinDTO -회원정보
      * @return HashMap<String, Object> - 회원정보 등록 결과
@@ -149,6 +175,13 @@
                 findByCheckEmail(params); // 이메일 중복 검사
             }
 
+            // 휴대폰번호로 기존 계정 확인 (기본 검사만 수행)
+            if (joinDTO.getMblTelno() != null && !joinDTO.getMblTelno().isEmpty()) {
+                HashMap<String, Object> params = new HashMap<>();
+                params.put("mblTelno", joinDTO.getMblTelno());
+                findByCheckMblTelno(params); // 휴대폰번호 중복 검사
+            }
+
             // 기존 회원가입 로직 실행
             return performStandardJoin(req, joinDTO);
 
src/main/java/com/takensoft/cms/mber/service/MberService.java
--- src/main/java/com/takensoft/cms/mber/service/MberService.java
+++ src/main/java/com/takensoft/cms/mber/service/MberService.java
@@ -38,6 +38,17 @@
      */
     public boolean findByCheckEmail(HashMap<String, Object> params);
 
+
+    /**
+     * @param params
+     *  - mblTelno: 휴대폰번호 정보
+     *  - mbrId: 회원 아이디
+     * @return boolean - 휴대폰번호 중복 여부
+     *
+     * 휴대폰번호 중복 검사
+     */
+    public boolean findByCheckMblTelno(HashMap<String, Object> params);
+
     /**
      * @param req - HTTP 요청 객체
      * @param joinDTO -회원정보
src/main/java/com/takensoft/cms/mber/web/MberController.java
--- src/main/java/com/takensoft/cms/mber/web/MberController.java
+++ src/main/java/com/takensoft/cms/mber/web/MberController.java
@@ -78,4 +78,19 @@
         // 응답 처리
         return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
     }
+
+    /**
+     * @param params - 휴대폰번호
+     * @return ResponseEntity - 휴대폰번호 중복 검사 결과
+     *
+     * 휴대폰번호 중복 검사
+     */
+    @PostMapping(value = "/findByCheckMblTelno.json")
+    public ResponseEntity<?> findByCheckMblTelno(@RequestBody HashMap<String, Object> params){
+        // 상세 조회
+        boolean result = mberService.findByCheckMblTelno(params);
+
+        // 응답 처리
+        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
+    }
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/certify/dao/EmailDAO.java (Renamed from src/main/java/com/takensoft/common/verify/dao/EmailDAO.java)
--- src/main/java/com/takensoft/common/verify/dao/EmailDAO.java
+++ src/main/java/com/takensoft/common/certify/dao/EmailDAO.java
@@ -1,10 +1,7 @@
-package com.takensoft.common.verify.dao;
+package com.takensoft.common.certify.dao;
 
-import com.takensoft.common.verify.vo.EmailVO;
 import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
 
-import java.util.HashMap;
-import java.util.List;
 /**
  * @author  : 하석형
  * @since   : 2025.05.20
 
src/main/java/com/takensoft/common/certify/dao/SMSDAO.java (added)
+++ src/main/java/com/takensoft/common/certify/dao/SMSDAO.java
@@ -0,0 +1,16 @@
+package com.takensoft.common.certify.dao;
+
+import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
+
+/**
+ * @author  : 하석형
+ * @since   : 2025.06.27
+ * @modification
+ *     since    |    author    | description
+ *  2025.06.27  |    하석형     | 최초 등록
+ *
+ * SMS 관련 Mapper
+ */
+@Mapper("smsDAO")
+public interface SMSDAO {
+}(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/certify/service/EmailService.java (Renamed from src/main/java/com/takensoft/common/verify/service/EmailService.java)
--- src/main/java/com/takensoft/common/verify/service/EmailService.java
+++ src/main/java/com/takensoft/common/certify/service/EmailService.java
@@ -1,10 +1,7 @@
-package com.takensoft.common.verify.service;
+package com.takensoft.common.certify.service;
 
-import com.takensoft.common.verify.vo.EmailVO;
-import org.springframework.web.multipart.MultipartFile;
+import com.takensoft.common.certify.vo.EmailVO;
 
-import java.util.HashMap;
-import java.util.List;
 /**
  * @author 하석형
  * @since 2025.05.20
@@ -21,7 +18,7 @@
      *
      * 이메일 인증코드 발송
      */
-    public boolean sendEmailVerifyCode(EmailVO emailVO);
+    public boolean sendEmailCertifyCode(EmailVO emailVO);
 
     /**
      * @param emailVO - 이메일 정보
@@ -29,5 +26,5 @@
      *
      * 이메일 인증코드 확인
      */
-    public boolean checkEmailVerifyCode(EmailVO emailVO);
+    public boolean checkEmailCertifyCode(EmailVO emailVO);
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/certify/service/Impl/EmailServiceImpl.java (Renamed from src/main/java/com/takensoft/common/verify/service/Impl/EmailServiceImpl.java)
--- src/main/java/com/takensoft/common/verify/service/Impl/EmailServiceImpl.java
+++ src/main/java/com/takensoft/common/certify/service/Impl/EmailServiceImpl.java
@@ -1,23 +1,17 @@
-package com.takensoft.common.verify.service.Impl;
+package com.takensoft.common.certify.service.Impl;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.takensoft.common.exception.*;
 import com.takensoft.common.util.JWTUtil;
-import com.takensoft.common.verify.dao.EmailDAO;
-import com.takensoft.common.verify.service.EmailService;
-import com.takensoft.common.verify.vo.EmailVO;
+import com.takensoft.common.certify.dao.EmailDAO;
+import com.takensoft.common.certify.service.EmailService;
+import com.takensoft.common.certify.vo.EmailVO;
 import lombok.RequiredArgsConstructor;
 import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.dao.DataAccessException;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.mail.SimpleMailMessage;
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import java.time.Duration;
 
@@ -43,22 +37,22 @@
     private final JavaMailSender mailSender;
     private final RedisTemplate<String, Object> redisTemplate;
 
-    @Value("${spring.mail.verifyTime}")
-    private long verifyTime; // 인증코드 유효시간
+    @Value("${spring.mail.certify-time}")
+    private long certifyTime; // 인증코드 유효시간
 
-    @Value("${spring.mail.storeTime}")
+    @Value("${spring.mail.store-time}")
     private long storeTime; // 인증코드 저장시간
 
     /**
      * @param emailVO - 이메일 정보
      * @return boolean - 이메일 인증코드 발송 결과
-     * @throws CustomEmailSendFailException - 이메일 발송 실패 시
+     * @throws CustomCertifySendFailException - 이메일 발송 실패 시
      * @throws Exception - 그 외 예외 발생 시
      *
      * 이메일 인증코드 발송
      */
     @Override
-    public boolean sendEmailVerifyCode(EmailVO emailVO) {
+    public boolean sendEmailCertifyCode(EmailVO emailVO) {
         try {
             String email = emailVO.getEmail();
             String code = createRandomCode(); // 인증코드 생성
@@ -80,7 +74,7 @@
             try {
                 mailSender.send(message);
             } catch (Exception e) {
-                throw new CustomEmailSendFailException("이메일 발송에 실패했습니다.");
+                throw new CustomCertifySendFailException("이메일 발송에 실패했습니다.");
             }
 
             redisTemplate.opsForValue().set("email:" + email, emailVO, Duration.ofMillis(storeTime)); // 인증코드 저장
@@ -94,15 +88,15 @@
     /**
      * @param emailVO - 이메일 정보
      * @return boolean - 이메일 인증코드 확인 결과
-     * @throws CustomEmailVerifyExpireException - 이메일 인증 만료 시
-     * @throws CustomEmailCodeNotMatchException - 이메일 인증코드 불일치 시
-     * @throws CustomEmailVerifyFailException - 이메일 인증 실패 시
+     * @throws CustomCertifyExpireException - 이메일 인증 만료 시
+     * @throws CustomCertifyCodeNotMatchException - 이메일 인증코드 불일치 시
+     * @throws CustomCertifyFailException - 이메일 인증 실패 시
      * @throws Exception - 그 외 예외 발생 시
      *
      * 이메일 인증코드 확인
      */
     @Override
-    public boolean checkEmailVerifyCode(EmailVO emailVO){
+    public boolean checkEmailCertifyCode(EmailVO emailVO){
         try {
             String email = emailVO.getEmail();
             String code = emailVO.getCode();
@@ -111,18 +105,18 @@
             boolean isSend = redisTemplate.hasKey("email:" + email); // 이메일 인증코드 발송여부 확인
 
             if(isSend) { // 이미 인증코드가 발송된 경우
-                EmailVO verifyVO = (EmailVO) redisTemplate.opsForValue().get("email:" + email); // 발송된 인증코드
-                if(currentAt - verifyVO.getCreatedAt() > verifyTime) { // 인증코드 유효시간이 지났을 경우
-                    throw new CustomEmailVerifyExpireException("인증 시간이 만료되었습니다.");
+                EmailVO certifyVO = (EmailVO) redisTemplate.opsForValue().get("email:" + email); // 발송된 인증코드
+                if(currentAt - certifyVO.getCreatedAt() > certifyTime) { // 인증코드 유효시간이 지났을 경우
+                    throw new CustomCertifyExpireException("인증 시간이 만료되었습니다.");
                 }
-                String verifyCode = verifyVO.getCode(); // 발송된 인증코드
-                if(verifyCode.equals(code)) { // 인증코드가 일치하는 경우
+                String certifyCode = certifyVO.getCode(); // 발송된 인증코드
+                if(certifyCode.equals(code)) { // 인증코드가 일치하는 경우
                     redisTemplate.delete("email:" + email); // 인증코드 삭제
                 } else { // 인증코드가 일치하지 않는 경우
-                    throw new CustomEmailCodeNotMatchException("인증코드가 일치하지 않습니다.");
+                    throw new CustomCertifyCodeNotMatchException("인증코드가 일치하지 않습니다.");
                 }
             } else { // 인증코드가 발송되지 않은 경우
-                throw new CustomEmailVerifyFailException("이메일 인증에 실패했습니다.");
+                throw new CustomCertifyFailException("이메일 인증에 실패했습니다.");
             }
             return true;
         } catch (Exception e) {
 
src/main/java/com/takensoft/common/certify/service/Impl/SMSServiceImpl.java (added)
+++ src/main/java/com/takensoft/common/certify/service/Impl/SMSServiceImpl.java
@@ -0,0 +1,157 @@
+package com.takensoft.common.certify.service.Impl;
+
+import com.takensoft.common.exception.CustomCertifyCodeNotMatchException;
+import com.takensoft.common.exception.CustomCertifySendFailException;
+import com.takensoft.common.exception.CustomCertifyExpireException;
+import com.takensoft.common.exception.CustomCertifyFailException;
+import com.takensoft.common.util.JWTUtil;
+import com.takensoft.common.certify.dao.SMSDAO;
+import com.takensoft.common.certify.service.SMSService;
+import com.takensoft.common.certify.vo.SMSVO;
+import lombok.RequiredArgsConstructor;
+import net.nurigo.sdk.NurigoApp;
+import net.nurigo.sdk.message.exception.NurigoMessageNotReceivedException;
+import net.nurigo.sdk.message.model.Message;
+import net.nurigo.sdk.message.service.DefaultMessageService;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.stereotype.Service;
+
+import java.time.Duration;
+
+
+/**
+ * @author 하석형
+ * @since 2025.06.27
+ * @modification
+ *     since    |    author    | description
+ *  2025.06.27  |    하석형     | 최초 등록
+ *
+ * EgovAbstractServiceImpl : 전자정부 상속
+ * SMSService : SMS 관련 인터페이스 상속
+ * 
+ * SMS 관련 인터페이스 구현체
+ */
+@Service("smsService")
+@RequiredArgsConstructor
+public class SMSServiceImpl extends EgovAbstractServiceImpl implements SMSService {
+
+    private final SMSDAO smsDAO;
+    private final JWTUtil jwtUtil;
+    private final JavaMailSender mailSender;
+    private final RedisTemplate<String, Object> redisTemplate;
+
+    @Value("${spring.sms.api-key}")
+    private String apiKey; // API 키
+
+    @Value("${spring.sms.api-secret}")
+    private String apiSecret; // API 시크릿 키
+
+    @Value("${spring.sms.sender-number}")
+    private String senderNumber; // 발신번호
+
+    @Value("${spring.sms.certify-time}")
+    private long certifyTime; // 인증코드 유효시간
+
+    @Value("${spring.sms.store-time}")
+    private long storeTime; // 인증코드 저장시간
+
+    /**
+     * @param smsVO - SMS 정보
+     * @return boolean - SMS 인증코드 발송 결과
+     * @throws CustomCertifySendFailException - SMS 발송 실패 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
+     * SMS 인증코드 발송
+     */
+    @Override
+    public boolean sendSMSCertifyCode(SMSVO smsVO) {
+        try {
+            String mblTelno = smsVO.getMblTelno();
+            String code = createRandomCode(); // 인증코드 생성
+            smsVO.setCode(code);
+            long currentAt = System.currentTimeMillis(); // 현재 시간(millis)
+            smsVO.setCreatedAt(currentAt);
+
+            boolean isSend = redisTemplate.hasKey("sms:" + mblTelno); // 이메일 인증코드 발송여부 확인
+
+            if (isSend) { // 이미 인증코드가 발송된 경우
+                redisTemplate.delete("sms:" + mblTelno); // 인증코드 삭제
+            }
+
+            // SMS 발송
+            DefaultMessageService messageService = NurigoApp.INSTANCE.initialize(apiKey, apiSecret, "https://api.solapi.com");
+            Message message = new Message();
+            message.setFrom(senderNumber); // 계정에서 등록한 발신번호 입력
+            message.setTo(mblTelno); // 수신번호 입력
+            message.setText("인증 코드는 " + code + " 입니다."); // SMS는 한글 45자, 영자 90자까지 입력할 수 있습니다.
+            try {
+                messageService.send(message); // send 메소드로 ArrayList<Message> 객체를 넣어도 동작합니다!
+            } catch (NurigoMessageNotReceivedException exception) {
+                // 발송에 실패한 메시지 목록을 확인할 수 있습니다!
+                System.out.println(exception.getFailedMessageList());
+                System.out.println(exception.getMessage());
+                throw new CustomCertifySendFailException("SMS 발송에 실패했습니다.");
+            } catch (Exception exception) {
+                System.out.println(exception.getMessage());
+                throw new CustomCertifySendFailException("SMS 발송에 실패했습니다.");
+            }
+
+            redisTemplate.opsForValue().set("sms:" + mblTelno, smsVO, Duration.ofMillis(storeTime)); // 인증코드 저장
+            return true;
+        } catch (Exception e) {
+            redisTemplate.delete("sms:" + smsVO.getMblTelno()); // 실패시 인증코드 삭제
+            throw e;
+        }
+    }
+
+    /**
+     * @param smsVO - SMS 정보
+     * @return boolean - SMS 인증코드 확인 결과
+     * @throws CustomCertifyExpireException - SMS 인증 만료 시
+     * @throws CustomCertifyCodeNotMatchException - SMS 인증코드 불일치 시
+     * @throws CustomCertifyFailException - SMS 인증 실패 시
+     * @throws Exception - 그 외 예외 발생 시
+     *
+     * SMS 인증코드 확인
+     */
+    @Override
+    public boolean checkSMSCertifyCode(SMSVO smsVO){
+        try {
+            String mblTelno = smsVO.getMblTelno();
+            String code = smsVO.getCode();
+            long currentAt = System.currentTimeMillis(); // 현재 시간(millis)
+
+            boolean isSend = redisTemplate.hasKey("sms:" + mblTelno); // SMS 인증코드 발송여부 확인
+
+            if(isSend) { // 이미 인증코드가 발송된 경우
+                SMSVO certifyVO = (SMSVO) redisTemplate.opsForValue().get("sms:" + mblTelno); // 발송된 인증코드
+                if(currentAt - certifyVO.getCreatedAt() > certifyTime) { // 인증코드 유효시간이 지났을 경우
+                    throw new CustomCertifyExpireException("인증 시간이 만료되었습니다.");
+                }
+                String certifyCode = certifyVO.getCode(); // 발송된 인증코드
+                if(certifyCode.equals(code)) { // 인증코드가 일치하는 경우
+                    redisTemplate.delete("sms:" + mblTelno); // 인증코드 삭제
+                } else { // 인증코드가 일치하지 않는 경우
+                    throw new CustomCertifyCodeNotMatchException("인증코드가 일치하지 않습니다.");
+                }
+            } else { // 인증코드가 발송되지 않은 경우
+                throw new CustomCertifyFailException("SMS 인증에 실패했습니다.");
+            }
+            return true;
+        } catch (Exception e) {
+            throw e;
+        }
+    }
+
+    /**
+     * @return String - SMS 인증코드
+     *
+     * SMS 인증코드 생성
+     */
+    private String createRandomCode() {
+        return String.valueOf((int)(Math.random() * 899999) + 100000); // 6자리 숫자
+    }
+}(파일 끝에 줄바꿈 문자 없음)
 
src/main/java/com/takensoft/common/certify/service/SMSService.java (added)
+++ src/main/java/com/takensoft/common/certify/service/SMSService.java
@@ -0,0 +1,30 @@
+package com.takensoft.common.certify.service;
+
+import com.takensoft.common.certify.vo.SMSVO;
+
+/**
+ * @author 하석형
+ * @since 2025.06.27
+ * @modification
+ *     since    |    author    | description
+ *  2025.06.27  |    하석형     | 최초 등록
+ *
+ * SMS 관련 인터페이스
+ */
+public interface SMSService {
+    /**
+     * @param smsVO - SMS 정보
+     * @return boolean - SMS 인증코드 발송 결과
+     *
+     * SMS 인증코드 발송
+     */
+    public boolean sendSMSCertifyCode(SMSVO smsVO);
+
+    /**
+     * @param smsVO - SMS 정보
+     * @return boolean - SMS 인증코드 확인 결과
+     *
+     * SMS 인증코드 확인
+     */
+    public boolean checkSMSCertifyCode(SMSVO smsVO);
+}(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/certify/vo/EmailVO.java (Renamed from src/main/java/com/takensoft/common/verify/vo/EmailVO.java)
--- src/main/java/com/takensoft/common/verify/vo/EmailVO.java
+++ src/main/java/com/takensoft/common/certify/vo/EmailVO.java
@@ -1,8 +1,6 @@
-package com.takensoft.common.verify.vo;
+package com.takensoft.common.certify.vo;
 
 import lombok.*;
-
-import java.time.LocalDateTime;
 
 /**
  * @author  : 하석형
src/main/java/com/takensoft/common/certify/vo/SMSVO.java (copied from src/main/java/com/takensoft/common/verify/vo/EmailVO.java)
--- src/main/java/com/takensoft/common/verify/vo/EmailVO.java
+++ src/main/java/com/takensoft/common/certify/vo/SMSVO.java
@@ -0,0 +1,26 @@
+package com.takensoft.common.certify.vo;
+
+import lombok.*;
+
+/**
+ * @author  : 하석형
+ * @since   : 2025.06.27
+ * @modification
+ *     since    |    author    | description
+ *  2025.06.27  |    하석형     | 최초 등록
+ *
+ * SMS 관련 VO
+ */
+@Setter
+@Getter
+@ToString
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SMSVO {
+    private String mbrId;       // 회원아이디
+    private String mblTelno;    // 휴대폰전화번호
+    private String code;        // 인증코드
+    private long createdAt;     // 인증코드 생성일시
+//    private LocalDateTime regDt;       // 등록일시
+}(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/certify/web/EmailController.java (Renamed from src/main/java/com/takensoft/common/verify/web/EmailController.java)
--- src/main/java/com/takensoft/common/verify/web/EmailController.java
+++ src/main/java/com/takensoft/common/certify/web/EmailController.java
@@ -1,21 +1,18 @@
-package com.takensoft.common.verify.web;
+package com.takensoft.common.certify.web;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.takensoft.cms.loginPolicy.service.LoginModeService;
 import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
 import com.takensoft.cms.mber.service.LgnHstryService;
 import com.takensoft.cms.mber.service.MberService;
-import com.takensoft.cms.mber.vo.LgnHstryVO;
 import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.cms.token.service.RefreshTokenService;
-import com.takensoft.cms.token.vo.RefreshTknVO;
 import com.takensoft.common.message.MessageCode;
 import com.takensoft.common.util.*;
-import com.takensoft.common.verify.service.EmailService;
-import com.takensoft.common.verify.vo.EmailVO;
+import com.takensoft.common.certify.service.EmailService;
+import com.takensoft.common.certify.vo.EmailVO;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
-import jakarta.servlet.http.HttpSession;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
@@ -23,17 +20,10 @@
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.net.URLEncoder;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 /**
  * @author 하석형
@@ -76,12 +66,12 @@
      *
      * 이메일 인증코드 발송
      */
-    @PostMapping("/sendEmailVerifyCode.json")
-    public ResponseEntity<?> sendEmailVerifyCode(@RequestBody EmailVO emailVO) {
+    @PostMapping("/sendEmailCertifyCode.json")
+    public ResponseEntity<?> sendEmailCertifyCode(@RequestBody EmailVO emailVO) {
 
-        boolean result = emailService.sendEmailVerifyCode(emailVO);
+        boolean result = emailService.sendEmailCertifyCode(emailVO);
 
-        return resUtil.successRes(result, MessageCode.EMAIL_SEND_SUCCESS);
+        return resUtil.successRes(result, MessageCode.CERTIFY_CODE_SEND_SUCCESS);
     }
 
     /**
@@ -90,12 +80,12 @@
      *
      * 이메일 인증코드 확인
      */
-    @PostMapping("/checkEmailVerifyCode.json")
-    public ResponseEntity<?> checkEmailVerifyCode(@RequestBody EmailVO emailVO) {
+    @PostMapping("/checkEmailCertifyCode.json")
+    public ResponseEntity<?> checkEmailCertifyCode(@RequestBody EmailVO emailVO) {
 
-        boolean result = emailService.checkEmailVerifyCode(emailVO);
+        boolean result = emailService.checkEmailCertifyCode(emailVO);
 
-        return resUtil.successRes(result, MessageCode.COMMON_SUCCESS);
+        return resUtil.successRes(result, MessageCode.CERTIFY_SUCCESS);
     }
 
     /**
@@ -104,10 +94,10 @@
      *
      * 2차 인증 이메일 인증코드 확인
      */
-    @PostMapping("/check2ndAuthEmailVerifyCode.json")
-    public void check2ndAuthEmailVerifyCode(@RequestBody EmailVO emailVO, HttpServletRequest req, HttpServletResponse res) throws IOException {
+    @PostMapping("/check2ndAuthEmailCertifyCode.json")
+    public void check2ndAuthEmailCertifyCode(@RequestBody EmailVO emailVO, HttpServletRequest req, HttpServletResponse res) throws IOException {
 
-        boolean authResult = emailService.checkEmailVerifyCode(emailVO); // 이메일 인증코드 확인
+        boolean authResult = emailService.checkEmailCertifyCode(emailVO); // 이메일 인증코드 확인
         if(authResult) {
             HashMap<String, Object> findMber = new HashMap<>();
             findMber.put("mbrId", emailVO.getMbrId());
 
src/main/java/com/takensoft/common/certify/web/SMSController.java (added)
+++ src/main/java/com/takensoft/common/certify/web/SMSController.java
@@ -0,0 +1,122 @@
+package com.takensoft.common.certify.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.takensoft.cms.loginPolicy.service.LoginModeService;
+import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
+import com.takensoft.cms.mber.service.LgnHstryService;
+import com.takensoft.cms.mber.service.MberService;
+import com.takensoft.cms.mber.vo.MberVO;
+import com.takensoft.cms.token.service.RefreshTokenService;
+import com.takensoft.common.message.MessageCode;
+import com.takensoft.common.util.*;
+import com.takensoft.common.certify.service.SMSService;
+import com.takensoft.common.certify.vo.SMSVO;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author 하석형
+ * @since 2025.05.20
+ * @modification
+ *     since    |    author    | description
+ *  2025.05.20  |    하석형     | 최초 등록
+ *
+ * SMS 관련 Controller
+ */
+@RestController
+@RequiredArgsConstructor
+@Slf4j
+@RequestMapping(value="/sys/sms")
+public class SMSController {
+
+    private final SMSService smsService;
+    private final ResponseUtil resUtil;
+    private final MberService mberService;
+    private final HttpRequestUtil httpRequestUtil;
+    private final LgnHstryService lgnHstryService;
+    private final LoginModeService loginModeService;
+    private final RefreshTokenService refreshTokenService;
+    private final LoginPolicyService loginPolicyService;
+    private final JWTUtil jwtUtil;
+    private final SessionUtil sessionUtil;
+    private final RedisTemplate<String, String> redisTemplate;
+    private final LoginUtil loginUtil;
+
+    @Value("${jwt.accessTime}")
+    private long JWT_ACCESSTIME;
+    @Value("${jwt.refreshTime}")
+    private long JWT_REFRESHTIME;
+    @Value("${cookie.time}")
+    private int COOKIE_TIME; // 쿠키 유지 시간
+
+    /**
+     * @param smsVO - SMS 정보
+     * @return ResponseEntity - SMS 인증코드 발송 응답 결과
+     *
+     * SMS 인증코드 발송
+     */
+    @PostMapping("/sendSMSCertifyCode.json")
+    public ResponseEntity<?> sendSMSCertifyCode(@RequestBody SMSVO smsVO) {
+
+        boolean result = smsService.sendSMSCertifyCode(smsVO);
+
+        return resUtil.successRes(result, MessageCode.CERTIFY_CODE_SEND_SUCCESS);
+    }
+
+    /**
+     * @param smsVO - SMS 정보
+     * @return ResponseEntity - SMS 인증코드 확인 응답 결과
+     *
+     * SMS 인증코드 확인
+     */
+    @PostMapping("/checkSMSCertifyCode.json")
+    public ResponseEntity<?> checkSMSCertifyCode(@RequestBody SMSVO smsVO) {
+
+        boolean result = smsService.checkSMSCertifyCode(smsVO);
+
+        return resUtil.successRes(result, MessageCode.CERTIFY_SUCCESS);
+    }
+
+    /**
+     * @param smsVO - SMS 정보
+     * @return ResponseEntity - SMS 인증코드 확인 응답 결과
+     *
+     * 2차 인증 SMS 인증코드 확인
+     */
+    @PostMapping("/check2ndAuthSMSCertifyCode.json")
+    public void check2ndAuthSMSCertifyCode(@RequestBody SMSVO smsVO, HttpServletRequest req, HttpServletResponse res) throws IOException {
+
+        boolean authResult = smsService.checkSMSCertifyCode(smsVO); // SMS 인증코드 확인
+        if(authResult) {
+            HashMap<String, Object> findMber = new HashMap<>();
+            findMber.put("mbrId", smsVO.getMbrId());
+            MberVO mber = mberService.findByMbr(findMber);
+
+            loginUtil.successLogin(mber, req, res);
+        } else {
+            // 인증 실패 시 예외 처리
+            Map<String, Object> result = new HashMap<>();
+            res.setContentType("application/json;charset=UTF-8");
+            res.setStatus(HttpStatus.UNAUTHORIZED.value());
+            result.put("message", "인증에 실패했습니다. 올바른 인증코드를 입력해주세요.");
+            new ObjectMapper().writeValue(res.getOutputStream(), result);
+            return;
+        }
+
+//        return resUtil.successRes(authResult, MessageCode.COMMON_SUCCESS);
+    }
+}
src/main/java/com/takensoft/common/config/CorsMvcConfig.java
--- src/main/java/com/takensoft/common/config/CorsMvcConfig.java
+++ src/main/java/com/takensoft/common/config/CorsMvcConfig.java
@@ -3,11 +3,14 @@
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.web.servlet.LocaleResolver;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
 
+import java.util.List;
 import java.util.Locale;
 
 /**
@@ -55,4 +58,13 @@
         resolver.setDefaultLocale(Locale.KOREA);
         return resolver;
     }
+    /**
+     * @param converters - HTTP 메시지 변환기를 관리하는 리스트
+     *
+     * HTTP 메시지 변환기를 설정 (Kotlin 관련 라이브러리의 Converter 우선 적용이 아닌, Jackson을 사용하여 JSON 변환을 처리)
+     */
+    @Override
+    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
+        converters.add(0, new MappingJackson2HttpMessageConverter());
+    }
 }
(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/config/SecurityConfig.java
--- src/main/java/com/takensoft/common/config/SecurityConfig.java
+++ src/main/java/com/takensoft/common/config/SecurityConfig.java
@@ -12,7 +12,7 @@
 import com.takensoft.common.exception.CustomAuthenticationEntryPoint;
 import com.takensoft.common.util.JWTUtil;
 import com.takensoft.common.util.LoginUtil;
-import com.takensoft.common.verify.service.Impl.EmailServiceImpl;
+import com.takensoft.common.certify.service.Impl.EmailServiceImpl;
 import com.takensoft.common.oauth.service.Impl.CustomOAuth2UserServiceImpl;
 import com.takensoft.common.oauth.handler.OAuth2AuthenticationSuccessHandler;
 import com.takensoft.common.oauth.handler.OAuth2AuthenticationFailureHandler;
 
src/main/java/com/takensoft/common/exception/CustomCertifyCodeNotMatchException.java (added)
+++ src/main/java/com/takensoft/common/exception/CustomCertifyCodeNotMatchException.java
@@ -0,0 +1,26 @@
+package com.takensoft.common.exception;
+
+/**
+ * @author takensoft
+ * @since 2025.05.21
+ * @modification
+ *     since    |    author    | description
+ *  2025.05.21  |    하석형     | 최초 등록
+ *
+ * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
+ *
+ * 인증코드 불일치 시 발생하는 예외
+ */
+public class CustomCertifyCodeNotMatchException extends RuntimeException {
+
+    public CustomCertifyCodeNotMatchException() {
+
+    }
+    public CustomCertifyCodeNotMatchException(String message) {
+        super(message);
+    }
+
+    public CustomCertifyCodeNotMatchException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
 
src/main/java/com/takensoft/common/exception/CustomCertifyExpireException.java (added)
+++ src/main/java/com/takensoft/common/exception/CustomCertifyExpireException.java
@@ -0,0 +1,26 @@
+package com.takensoft.common.exception;
+
+/**
+ * @author takensoft
+ * @since 2025.05.21
+ * @modification
+ *     since    |    author    | description
+ *  2025.05.21  |    하석형     | 최초 등록
+ *
+ * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
+ *
+ * 인증시간 만료 시 발생하는 예외
+ */
+public class CustomCertifyExpireException extends RuntimeException {
+
+    public CustomCertifyExpireException() {
+
+    }
+    public CustomCertifyExpireException(String message) {
+        super(message);
+    }
+
+    public CustomCertifyExpireException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
 
src/main/java/com/takensoft/common/exception/CustomCertifyFailException.java (added)
+++ src/main/java/com/takensoft/common/exception/CustomCertifyFailException.java
@@ -0,0 +1,26 @@
+package com.takensoft.common.exception;
+
+/**
+ * @author takensoft
+ * @since 2025.05.21
+ * @modification
+ *     since    |    author    | description
+ *  2025.05.21  |    하석형     | 최초 등록
+ *
+ * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
+ *
+ * 인증 실패 시 발생하는 예외
+ */
+public class CustomCertifyFailException extends RuntimeException {
+
+    public CustomCertifyFailException() {
+
+    }
+    public CustomCertifyFailException(String message) {
+        super(message);
+    }
+
+    public CustomCertifyFailException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
 
src/main/java/com/takensoft/common/exception/CustomCertifySendFailException.java (added)
+++ src/main/java/com/takensoft/common/exception/CustomCertifySendFailException.java
@@ -0,0 +1,26 @@
+package com.takensoft.common.exception;
+
+/**
+ * @author takensoft
+ * @since 2025.05.21
+ * @modification
+ *     since    |    author    | description
+ *  2025.05.21  |    하석형     | 최초 등록
+ *
+ * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
+ *
+ * 인증 발송 실패 시 발생하는 예외
+ */
+public class CustomCertifySendFailException extends RuntimeException {
+
+    public CustomCertifySendFailException() {
+
+    }
+    public CustomCertifySendFailException(String message) {
+        super(message);
+    }
+
+    public CustomCertifySendFailException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
 
src/main/java/com/takensoft/common/exception/CustomEmailCodeNotMatchException.java (deleted)
--- src/main/java/com/takensoft/common/exception/CustomEmailCodeNotMatchException.java
@@ -1,26 +0,0 @@
-package com.takensoft.common.exception;
-
-/**
- * @author takensoft
- * @since 2025.05.21
- * @modification
- *     since    |    author    | description
- *  2025.05.21  |    하석형     | 최초 등록
- *
- * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
- *
- * 이메일 인증코드 불일치 시 발생하는 예외
- */
-public class CustomEmailCodeNotMatchException extends RuntimeException {
-
-    public CustomEmailCodeNotMatchException() {
-
-    }
-    public CustomEmailCodeNotMatchException(String message) {
-        super(message);
-    }
-
-    public CustomEmailCodeNotMatchException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
 
src/main/java/com/takensoft/common/exception/CustomEmailSendFailException.java (deleted)
--- src/main/java/com/takensoft/common/exception/CustomEmailSendFailException.java
@@ -1,26 +0,0 @@
-package com.takensoft.common.exception;
-
-/**
- * @author takensoft
- * @since 2025.05.21
- * @modification
- *     since    |    author    | description
- *  2025.05.21  |    하석형     | 최초 등록
- *
- * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
- *
- * 이메일 발송 실패 시 발생하는 예외
- */
-public class CustomEmailSendFailException extends RuntimeException {
-
-    public CustomEmailSendFailException() {
-
-    }
-    public CustomEmailSendFailException(String message) {
-        super(message);
-    }
-
-    public CustomEmailSendFailException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
 
src/main/java/com/takensoft/common/exception/CustomEmailVerifyExpireException.java (deleted)
--- src/main/java/com/takensoft/common/exception/CustomEmailVerifyExpireException.java
@@ -1,26 +0,0 @@
-package com.takensoft.common.exception;
-
-/**
- * @author takensoft
- * @since 2025.05.21
- * @modification
- *     since    |    author    | description
- *  2025.05.21  |    하석형     | 최초 등록
- *
- * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
- *
- * 이메일 인증시간 만료 시 발생하는 예외
- */
-public class CustomEmailVerifyExpireException extends RuntimeException {
-
-    public CustomEmailVerifyExpireException() {
-
-    }
-    public CustomEmailVerifyExpireException(String message) {
-        super(message);
-    }
-
-    public CustomEmailVerifyExpireException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
 
src/main/java/com/takensoft/common/exception/CustomEmailVerifyFailException.java (deleted)
--- src/main/java/com/takensoft/common/exception/CustomEmailVerifyFailException.java
@@ -1,26 +0,0 @@
-package com.takensoft.common.exception;
-
-/**
- * @author takensoft
- * @since 2025.05.21
- * @modification
- *     since    |    author    | description
- *  2025.05.21  |    하석형     | 최초 등록
- *
- * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
- *
- * 이메일 인증 실패 시 발생하는 예외
- */
-public class CustomEmailVerifyFailException extends RuntimeException {
-
-    public CustomEmailVerifyFailException() {
-
-    }
-    public CustomEmailVerifyFailException(String message) {
-        super(message);
-    }
-
-    public CustomEmailVerifyFailException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
 
src/main/java/com/takensoft/common/exception/CustomMblTelnoTakenException.java (added)
+++ src/main/java/com/takensoft/common/exception/CustomMblTelnoTakenException.java
@@ -0,0 +1,28 @@
+package com.takensoft.common.exception;
+
+/**
+ * @author 하석형
+ * @since 2025.06.30
+ * @modification
+ *     since    |    author    | description
+ *  2025.06.30  |    하석형     | 최초 등록
+ *
+ * RuntimeException - 실행 중 발생하는 예외를 처리하는 기본 클래스
+ *
+ * 회원가입 시 휴대폰번호 중복으로 발생하는 예외
+ */
+public class CustomMblTelnoTakenException extends RuntimeException {
+
+    public CustomMblTelnoTakenException() {
+
+    }
+
+    public CustomMblTelnoTakenException(String message) {
+        super(message);
+    }
+
+    public CustomMblTelnoTakenException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}(파일 끝에 줄바꿈 문자 없음)
src/main/java/com/takensoft/common/exception/GlobalExceptionHandler.java
--- src/main/java/com/takensoft/common/exception/GlobalExceptionHandler.java
+++ src/main/java/com/takensoft/common/exception/GlobalExceptionHandler.java
@@ -329,46 +329,46 @@
      *
      * CustomEmailSendFailException이 발생한 경우
      */
-    @ExceptionHandler(CustomEmailSendFailException.class)
-    public ResponseEntity<?> handleCustomEmailSendFailException(CustomEmailSendFailException cesfe) {
+    @ExceptionHandler(CustomCertifySendFailException.class)
+    public ResponseEntity<?> handleCustomEmailSendFailException(CustomCertifySendFailException cesfe) {
         logError(cesfe);
-        return resUtil.errorRes(MessageCode.EMAIL_SEND_FAIL);
+        return resUtil.errorRes(MessageCode.CERTIFY_CODE_SEND_FAIL);
     }
 
     /**
-     * @param cevee - CustomEmailVerifyExpireException 예외 객체
-     * @return CustomEmailVerifyExpireException에 대한 HTTP 응답
+     * @param cevee - CustomCertifyExpireException 예외 객체
+     * @return CustomCertifyExpireException에 대한 HTTP 응답
      *
-     * CustomEmailVerifyExpireException이 발생한 경우
+     * CustomCertifyExpireException이 발생한 경우
      */
-    @ExceptionHandler(CustomEmailVerifyExpireException.class)
-    public ResponseEntity<?> handleCustomEmailVerifyExpireException(CustomEmailVerifyExpireException cevee) {
+    @ExceptionHandler(CustomCertifyExpireException.class)
+    public ResponseEntity<?> handleCustomCertifyExpireException(CustomCertifyExpireException cevee) {
         logError(cevee);
-        return resUtil.errorRes(MessageCode.EMAIL_VERIFY_EXPIRED);
+        return resUtil.errorRes(MessageCode.CERTIFY_EXPIRED);
     }
 
     /**
-     * @param cevfe - CustomEmailVerifyFailException 예외 객체
-     * @return CustomEmailVerifyFailException에 대한 HTTP 응답
+     * @param cevfe - CustomCertifyFailException 예외 객체
+     * @return CustomCertifyFailException에 대한 HTTP 응답
      *
-     * CustomEmailVerifyFailException이 발생한 경우
+     * CustomCertifyFailException 발생한 경우
      */
-    @ExceptionHandler(CustomEmailVerifyFailException.class)
-    public ResponseEntity<?> handleCustomEmailVerifyFailException(CustomEmailVerifyFailException cevfe) {
+    @ExceptionHandler(CustomCertifyFailException.class)
+    public ResponseEntity<?> handleCustomCertifyFailException(CustomCertifyFailException cevfe) {
         logError(cevfe);
-        return resUtil.errorRes(MessageCode.EMAIL_VERIFY_FAIL);
+        return resUtil.errorRes(MessageCode.CERTIFY_FAIL);
     }
 
     /**
-     * @param cecnme - CustomEmailCodeNotMatchException 예외 객체
-     * @return CustomEmailCodeNotMatchException에 대한 HTTP 응답
+     * @param cecnme - CustomCertifyCodeNotMatchException 예외 객체
+     * @return CustomCertifyCodeNotMatchException에 대한 HTTP 응답
      *
-     * CustomEmailCodeNotMatchException이 발생한 경우
+     * CustomCertifyCodeNotMatchException이 발생한 경우
      */
-    @ExceptionHandler(CustomEmailCodeNotMatchException.class)
-    public ResponseEntity<?> handleCustomEmailCodeNotMatchException(CustomEmailCodeNotMatchException cecnme) {
+    @ExceptionHandler(CustomCertifyCodeNotMatchException.class)
+    public ResponseEntity<?> handleCustomCertifyCodeNotMatchException(CustomCertifyCodeNotMatchException cecnme) {
         logError(cecnme);
-        return resUtil.errorRes(MessageCode.CODE_NOT_MATCH);
+        return resUtil.errorRes(MessageCode.CERTIFY_CODE_NOT_MATCH);
     }
 
     /**
@@ -384,6 +384,18 @@
     }
 
     /**
+     * @param cmtte - CustomMblTelnoTakenException 예외 객체
+     * @return CustomMblTelnoTakenException에 대한 HTTP 응답
+     *
+     * CustomMblTelnoTakenException 발생한 경우
+     */
+    @ExceptionHandler(CustomMblTelnoTakenException.class)
+    public ResponseEntity<?> handleCustomMblTelnoTakenException(CustomMblTelnoTakenException cmtte) {
+        logError(cmtte);
+        return resUtil.errorRes(MessageCode.SIGNUP_MBL_TELNO_TAKEN);
+    }
+
+    /**
      * @param e - Exception 예외 객체
      * @return 기타 예외에 대한 HTTP 응답
      *
src/main/java/com/takensoft/common/filter/LoginFilter.java
--- src/main/java/com/takensoft/common/filter/LoginFilter.java
+++ src/main/java/com/takensoft/common/filter/LoginFilter.java
@@ -6,8 +6,8 @@
 import com.takensoft.cms.mber.vo.MberVO;
 import com.takensoft.common.exception.FilterExceptionHandler;
 import com.takensoft.common.util.LoginUtil;
-import com.takensoft.common.verify.service.Impl.EmailServiceImpl;
-import com.takensoft.common.verify.vo.EmailVO;
+import com.takensoft.common.certify.service.Impl.EmailServiceImpl;
+import com.takensoft.common.certify.vo.EmailVO;
 import lombok.SneakyThrows;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.authentication.AuthenticationManager;
@@ -85,7 +85,7 @@
             EmailVO emailVO = new EmailVO().builder()
                     .email(mber.getEml())
                     .build();
-            emailServiceImpl.sendEmailVerifyCode(emailVO);
+            emailServiceImpl.sendEmailCertifyCode(emailVO);
 
             result.put("mbrId", mber.getMbrId());
             result.put("email", mber.getEml());
src/main/java/com/takensoft/common/message/MessageCode.java
--- src/main/java/com/takensoft/common/message/MessageCode.java
+++ src/main/java/com/takensoft/common/message/MessageCode.java
@@ -56,6 +56,7 @@
     SIGNUP_SUCCESS("user.signup.success", HttpStatus.OK),    // 회원가입 성공
     SIGNUP_ID_TAKEN("user.signup.id_taken", HttpStatus.CONFLICT),   // 아이디 중복
     SIGNUP_EMAIL_TAKEN("user.signup.email_taken", HttpStatus.CONFLICT), // 이메일 중복
+    SIGNUP_MBL_TELNO_TAKEN("user.signup.mbl_telno_taken", HttpStatus.CONFLICT), // 휴대폰번호 중복
     LOGIN_USER_NOT_FOUND("user.login.user_not_found", HttpStatus.NOT_FOUND), // 사용자가 존재 하지 않는 경우
     LOGIN_INVALID_CREDENTIALS("user.login.invalid_credentials", HttpStatus.UNAUTHORIZED), // 비밀번호 불일치
     LOGIN_AUTHENTICATION_REQUIRED("user.login.authentication_required", HttpStatus.FORBIDDEN), // 인증 거부
@@ -68,13 +69,13 @@
     // 파일 관련
     FILE_UPLOAD_FAIL("file.upload_fail", HttpStatus.INTERNAL_SERVER_ERROR), // 파일 업로드 실패
 
-    // 이메일 인증 관련
-    EMAIL_SEND_SUCCESS("email.send_success", HttpStatus.OK), // 이메일 발송 성공
-    EMAIL_SEND_FAIL("email.send_fail", HttpStatus.INTERNAL_SERVER_ERROR), // 이메일 발송 실패
-    EMAIL_VERIFY_SUCCESS("email.verify_success", HttpStatus.OK), // 이메일 인증 성공
-    EMAIL_VERIFY_EXPIRED("email.verify_expired", HttpStatus.UNAUTHORIZED), // 이메일 인증 만료
-    EMAIL_VERIFY_FAIL("email.verify_fail", HttpStatus.UNAUTHORIZED), // 이메일 인증 실패
-    CODE_NOT_MATCH("email.code_not_match", HttpStatus.UNAUTHORIZED), // 인증 코드 불일치
+    // 인증 관련
+    CERTIFY_CODE_SEND_SUCCESS("certify.send_success", HttpStatus.OK), // 인증 코드 발송 성공
+    CERTIFY_CODE_SEND_FAIL("certify.send_fail", HttpStatus.INTERNAL_SERVER_ERROR), // 인증 코드 발송 실패
+    CERTIFY_SUCCESS("certify.certify_success", HttpStatus.OK), // 인증 성공
+    CERTIFY_EXPIRED("certify.certify_expired", HttpStatus.UNAUTHORIZED), // 인증 만료
+    CERTIFY_FAIL("certify.certify_fail", HttpStatus.UNAUTHORIZED), // 인증 실패
+    CERTIFY_CODE_NOT_MATCH("certify.code_not_match", HttpStatus.UNAUTHORIZED), // 인증 코드 불일치
 
     //소셜 로그인 관련
     OAUTH2_LOGIN_ERROR("oauth2.login_error", HttpStatus.INTERNAL_SERVER_ERROR), //소셜 로그인 실패
src/main/resources/application.yml
--- src/main/resources/application.yml
+++ src/main/resources/application.yml
@@ -62,8 +62,16 @@
           auth: true
           starttls: # 데이터 암호화 관련
             enable: true
-    verifyTime: 600000 # 인증가능 시간: 10분
-    storeTime: 86400000 # 보관 시간: 24시간
+    certify-time: 600000 # 인증가능 시간: 10분
+    store-time: 86400000 # 보관 시간: 24시간
+
+  # SMS 인증
+  sms:
+    api-key: NCSC5VEIMOYDW3RC
+    api-secret: FJ9YOUOELWSXDZO9MAFMPXPU6IFZS7PG
+    sender-number: "01051054225"
+    certify-time: 600000 # 인증가능 시간: 10분
+    store-time: 86400000 # 보관 시간: 24시간
 
   # OAuth2 설정 추가
   security:
src/main/resources/message/messages_en.yml
--- src/main/resources/message/messages_en.yml
+++ src/main/resources/message/messages_en.yml
@@ -43,6 +43,7 @@
   signup:
     id_taken: "The userid is already in use."
     email_taken: "The email is already in use."
+    mbl_telno_taken: "The mobile phone number is already in use."
     success: "Registration completed successfully."
   login:
     user_not_found: "User information does not exist."
@@ -59,14 +60,14 @@
 file:
   upload_fail: "File upload failed."
 
-# 이메일 인증 관련
-email:
-  send_success: "Email sent successfully."
-  send_fail: "Failed to send email."
-  verify_success: "Email verification completed successfully."
-  verify_expired: "Email verification has expired."
-  verify_fail: "Email verification failed."
-  code_not_match: "verification code does not match."
+# 인증 관련
+certify:
+  send_success: "Sent successfully."
+  send_fail: "Failed to send."
+  certify_success: "Certification completed successfully."
+  certify_expired: "Certification has expired."
+  certify_fail: "Certification failed."
+  code_not_match: "Certification code does not match."
 
 # 소셜로그인 관련
 oauth2:
src/main/resources/message/messages_ko.yml
--- src/main/resources/message/messages_ko.yml
+++ src/main/resources/message/messages_ko.yml
@@ -44,6 +44,7 @@
   signup:
     id_taken: "이미 사용중인 아이디입니다."
     email_taken: "이미 사용중인 이메일입니다."
+    mbl_telno_taken: "이미 사용중인 이메일입니다."
     success: "회원가입이 정상처리 되었습니다."
   login:
     user_not_found: "회원정보가 존재하지 않습니다."
@@ -60,13 +61,13 @@
 file:
   upload_fail: "파일 업로드에 실패했습니다."
 
-# 이메일 인증 관련
-email:
-  send_success: "이메일을 발송했습니다."
-  send_fail: "이메일 발송에 실패했습니다."
-  verify_success: "이메일 인증이 완료되었습니다."
-  verify_expired: "인증 시간이 만료되었습니다."
-  verify_fail: "이메일 인증에 실패했습니다."
+# 인증 관련
+certify:
+  send_success: "인증 코드를 발송했습니다."
+  send_fail: "인증 코드 발송에 실패했습니다."
+  certify_success: "인증이 완료되었습니다."
+  certify_expired: "인증 시간이 만료되었습니다."
+  certify_fail: "인증에 실패했습니다."
   code_not_match: "인증 코드가 일치하지 않습니다."
 
 # 소셜로그인 관련
src/main/resources/mybatis/mapper/mber/admMbr-SQL.xml
--- src/main/resources/mybatis/mapper/mber/admMbr-SQL.xml
+++ src/main/resources/mybatis/mapper/mber/admMbr-SQL.xml
@@ -295,6 +295,19 @@
     </select>
 
     <!--
+        작 성 자 : 하석형
+        작 성 일 : 2025.06.27
+        내   용 : 휴대폰번호로 아이디 찾기 (로그인 아이디)
+    -->
+    <select id="lgnIdSearchByMblTelno" parameterType="AdmMbrDTO" resultType="String">
+        SELECT lgn_id
+        FROM mbr_info
+        WHERE mbr_nm = #{mbrNm}
+          AND mbl_telno = #{mblTelno}
+          AND use_yn = 'Y'
+    </select>
+
+    <!--
         작 성 자 : 박정하
         작 성 일 : 2024.07.03
         내   용 : 아이디 찾기 (회원 아이디)
src/main/resources/mybatis/mapper/mber/mber-SQL.xml
--- src/main/resources/mybatis/mapper/mber/mber-SQL.xml
+++ src/main/resources/mybatis/mapper/mber/mber-SQL.xml
@@ -306,6 +306,20 @@
         </if>
     </select>
 
+    <!-- 휴대폰번호로 사용자 조회 -->
+    <select id="findByMblTelno" parameterType="map" resultType="MberVO">
+        <include refid="selectMber" />
+        WHERE mi.mbl_telno = #{mblTelno}
+        AND mi.use_yn = 'Y'
+        AND mi.mbr_stts = '1'
+        <if test="mbrNm != null and mbrNm != ''">
+            AND mi.mbr_nm = #{mbrNm}
+        </if>
+        <if test="mbrId != null and mbrId != ''">
+            AND mi.mbr_id != #{mbrId}
+        </if>
+    </select>
+
     <!-- 이메일과 회원 유형으로 사용자 조회 -->
     <select id="findByEmailAndProvider" parameterType="map" resultMap="mberMap">
         <include refid="selectMber" />
Add a comment
List