Search
📲

Cool SMS 로 문자 인증 구현하기

태그
SMS
문자 인증
분류
Spring Boot
스타벅스 클론코딩을 진행하던 중, 문자 인증을 구현해야 하는 상황이 생겼습니다. 스타벅스 어플의 경우, 회원가입이나 유저 정보를 바꿀 때 문자 인증을 통해 유저 인증을 합니다. 하지만, 따로 사업장을 운영하는것이 아니라 mocking 을 하는 것이기 때문에 Cool SMS 를 사용하게 되었습니다.

Cool SMS 가입하기

먼저, https://coolsms.co.kr/ 에 들어가서 회원 가입을 해주세요.

apikey 와 apiSecretKey 발급하기

대시보드의 개발/연동 메뉴로 가서 apiKey 와 apiSecretKey 를 발급받아 주세요. 발급받은 키는 application.yml 에 아래와 같이 적어주세요.
sendNumber 를 넣지 않으면 오류가 나타나므로 이 점 주의해 주세요. 이때 sendNumber 는 실제 존재하는 휴대폰 번호 여야 합니다.
coolsms: api: key: ${COOLSMS_KEY} secret: ${COOLSMS_SECRET_KEY} sendNumber: ${SEND_NUMBER}
Plain Text
복사

문자 인증 구현하기

SMSMessageDTO.java

기본적으로 coolSMS 는 유저 이름과 핸드폰 번호를 받습니다.
public record SMSMessageDTO(String username, String phoneNumber) {}
Java
복사

SMSVerificationDTO.java

인증번호가 발급된 후, 인증번호를 받아올 DTO 입니다.
@Getter @Builder @AllArgsConstructor @NoArgsConstructor public class SMSVerificationDTO { private String username; private String phoneNumber; private String verificationCode; }
Java
복사

SMSMessageUtil.java

저의 경우, {핸드폰 번호:인증 번호} 쌍을 레디스에 저장하였습니다.
인증 DTO 가 왔을 때, 유저를 확인하기 위해서 입니다.
레디스를 사용하므로써 데이터의 유효 기간을 설정할 수 있습니다.
@Component @RequiredArgsConstructor @Slf4j public class SMSMessageUtil { @Value("${coolsms.api.key}") private String apikey; @Value("${coolsms.api.secret}") private String apiSecretKey; @Value("${sendNumber}") private String sender; private DefaultMessageService messageService; private final RedisUtil redisUtil; private final UserRepository userRepository; @PostConstruct private void init() { this.messageService = NurigoApp .INSTANCE .initialize(apikey, apiSecretKey, "https://api.coolsms.co.kr"); } public void verificationUser(SMSMessageDTO smsMessageDTO){ String username = smsMessageDTO.username(); String phoneNumber = smsMessageDTO.phoneNumber(); Optional<User> user = userRepository.findUserByUsernameAndPhoneNumber(username, phoneNumber); if(user.isPresent()) { throw new EntityExistsException(); } } public SingleMessageSentResponse sendMessage(String sendTo, String verificationCode) { Message message = new Message(); message.setFrom(sender); message.setTo(sendTo); message.setText("[스타벅스] 인증번호는 " + verificationCode + " 입니다. 정확히 입력해주세요."); SingleMessageSentResponse response = this.messageService .sendOne(new SingleMessageSendingRequest(message)); log.info("======================================================"); log.info("SMSMessage sent to: " + sendTo); log.info("======================================================"); return response; } public String generateVerificationCode() { Random random = new Random(); int randomNumber = 100000 + random.nextInt(900000); return String.valueOf(randomNumber); } public void saveDataForCheckUser(String phoneNumber, String verificationCode) { redisUtil.setDataWithExpire(phoneNumber, verificationCode, Duration.ofMinutes(5)); log.info("======================================================"); log.info("CheckRedisKeyValue: " + redisUtil.getData(phoneNumber)); log.info("======================================================"); } }
Java
복사

SMSMessageService.java

이 서비스에는 아래와 같은 메서드를 만들어 주었습니다.
회원가입 전, 인증 번호를 전송하는 메서드
회원가입 전, 받은 인증 번호와 보낸 인증 번호가 일치하는지 확인하는 메서드
@Service @RequiredArgsConstructor public class SMSMessageService { private final SMSMessageUtil smsMessageUtil; private final RedisUtil redisUtil; public void getSMSVerificationBeforeSignUp(SMSMessageDTO smsMessageDTO){ smsMessageUtil.verificationUser(smsMessageDTO); String verificationCode = smsMessageUtil.generateVerificationCode(); String phoneNumber = smsMessageDTO.phoneNumber(); smsMessageUtil.sendMessage(phoneNumber, verificationCode); smsMessageUtil.saveDataForCheckUser(phoneNumber, verificationCode); } public void checkUserUsingVerificationCode(String phoneNumber, String verificationCode) throws BadRequestException { String redisValue = redisUtil.getData(phoneNumber); if (!redisValue.equals(verificationCode)) { throw new BadRequestException(); } } }
Java
복사

SMSMessageController.java

@RestController @RequestMapping(value = "/api/v1/auth/sms") @RequiredArgsConstructor public class SMSController { private final SMSMessageService smsMessageService; @PostMapping(value = "/send") public ResponseEntity<?> sendSMSForVerification(@RequestBody @Valid SMSMessageDTO smsMessageDTO) throws Exception { smsMessageService.getSMSVerificationBeforeSignUp(smsMessageDTO); return ResponseEntity.ok(smsMessageDTO); } @PostMapping(value = "/check") public ResponseEntity<?> checkUserUsingVerificationCode(@RequestBody SMSVerificationDTO smsVerificationDTO) throws Exception { smsMessageService.checkUserUsingVerificationCode(smsVerificationDTO.getPhoneNumber() , smsVerificationDTO.getVerificationCode()); return ResponseEntity.ok(smsVerificationDTO); } }
Java
복사

결과

위와 같이 구현한 후, /api/v1/auth/sms 에 알맞은 Request 를 보내면 yml 에 등록한 번호에서 아래와 같이 문자가 옵니다.