Cool SMS 로 문자 인증 구현하기
문자 인증을 구현해보고 싶은데, 사업자 등록을 하지 않았다면? cool SMS 를 사용해보세요.
1. 준비하기
스타벅스 클론코딩을 진행하던 중, 문자 인증을 구현해야 하는 상황이 생겼습니다. 스타벅스 어플의 경우, 회원가입이나 유저 정보를 바꿀 때 문자 인증을 통해 유저 인증을 합니다. 하지만, 따로 사업장을 운영하는것이 아니라 mocking 을 하는 것이기 때문에 Cool SMS 를 사용하게 되었습니다.
1.1. Cool SMS 가입하기
먼저, cool sms 사이트 에 들어가서 회원 가입을 해주세요.
1.2. apikey 와 apiSecretKey 발급하기
- 대시보드의 개발/연동 메뉴로 가서 apiKey 와 apiSecretKey 를 발급받아 주세요. 발급받은 키는 application.yml 에 아래와 같이 적어주세요.
- sendNumber 를 넣지 않으면 오류가 나타나므로 이 점 주의해 주세요. 이때 sendNumber 는 실제 존재하는 휴대폰 번호 여야 합니다.
coolsms:
api:
key: ${COOLSMS_KEY}
secret: ${COOLSMS_SECRET_KEY}
sendNumber: ${SEND_NUMBER}
2. 문자 인증 구현하기
2.1. SMSMessageDTO.java
기본적으로 coolSMS 는 유저 이름과 핸드폰 번호를 받습니다.

1
public record SMSMessageDTO(String username, String phoneNumber) {}
SMSVerificationDTO.java
인증번호가 발급된 후, 인증번호를 받아올 DTO 입니다.

1
2
3
4
5
6
7
8
9
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SMSVerificationDTO {
private String username;
private String phoneNumber;
private String verificationCode;
}
2.2. SMSMessageUtil.java
저의 경우, {핸드폰 번호:인증 번호}
쌍을 레디스에 저장하였습니다.
- 인증 DTO 가 왔을 때, 유저를 확인하기 위해서 입니다.
- 레디스를 사용하므로써 데이터의 유효 기간을 설정할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@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("======================================================");
}
}
2.3. SMSMessageService.java
이 서비스에는 아래와 같은 메서드를 만들어 주었습니다.
- 회원가입 전, 인증 번호를 전송하는 메서드
- 회원가입 전, 받은 인증 번호와 보낸 인증 번호가 일치하는지 확인하는 메서드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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();
}
}
}
2.4. SMSMessageController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@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);
}
}
3. 결과
위와 같이 구현한 후, /api/v1/auth/sms
에 알맞은 Request 를 보내면 yml 에 등록한 번호에서 아래와 같이 문자가 옵니다.
This post is licensed under
CC BY 4.0
by the author.