Project/[Team]외국인 관광객을 위한 카드 플랫폼
[Spring Boot/React] CoolSMS API 사용해 문자 인증 구현
dbfl9911
2024. 8. 24. 19:49
- 백엔드 코드 (Spring Boot)
1. buil.gradle에 아래 코드 추가
implementation 'net.nurigo:sdk:4.2.7'
2. application.yaml에 아래 코드 추가
coolsms:
api:
key: 쿨SMS에서 받은 API키
secret: 쿨SMS에서 받은 SECRET키
number: 핸드폰 번호
3. Controller 코드 작성
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.nurigo.sdk.NurigoApp;
import net.nurigo.sdk.message.model.Message;
import net.nurigo.sdk.message.request.SingleMessageSendingRequest;
import net.nurigo.sdk.message.response.SingleMessageSentResponse;
import net.nurigo.sdk.message.service.DefaultMessageService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@RestController
public class SMSController {
private DefaultMessageService messageService;
private Map<String, String> verificationCodes = new HashMap<>(); // 전화번호별 인증번호 저장
@Value("${coolsms.api.key}")
private String apiKey;
@Value("${coolsms.api.secret}")
private String apiSecret;
@Value("${coolsms.api.number}")
private String fromNumber;
@PostConstruct
public void init() {
this.messageService = NurigoApp.INSTANCE.initialize(apiKey, apiSecret, "https://api.coolsms.co.kr");
}
/**
* 단일 메시지 발송 예제
*/
@PostMapping("/send-one")
public SingleMessageSentResponse sendOne(@RequestBody SMSRequest smsRequest) {
String phoneNumber = smsRequest.getPhoneNumber();
String verificationCode = generateVerificationCode();
verificationCodes.put(phoneNumber, verificationCode); // 전화번호와 인증번호 매핑
Message message = new Message();
message.setFrom(fromNumber);
message.setTo(phoneNumber);
message.setText("인증번호는 " + verificationCode + "입니다.");
SingleMessageSentResponse response = this.messageService.sendOne(new SingleMessageSendingRequest(message));
System.out.println(response);
return response;
}
/**
* 인증번호 확인 예제
*/
@PostMapping("/verify-code")
public boolean verifyCode(@RequestBody VerificationRequest verificationRequest) {
String sentCode = verificationCodes.get(verificationRequest.getPhoneNumber());
return verificationRequest.getVerificationCode().equals(sentCode);
}
private String generateVerificationCode() {
Random random = new Random();
int code = 100000 + random.nextInt(900000); // 100000 ~ 999999 사이의 랜덤 6자리 숫자 생성
return String.valueOf(code);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class SMSRequest {
private String phoneNumber;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class VerificationRequest {
private String phoneNumber;
private String verificationCode;
}
- 프론트 코드 (React)
import React, { useState } from 'react';
import { Input, Button } from '@mui/material';
import axios from 'axios';
function Card2() {
// 상태 관리: 휴대전화 번호, 인증번호, 인증번호 발송 여부, 인증 성공 여부
const [phoneNumber, setPhoneNumber] = useState(''); // 입력된 휴대전화 번호
const [verificationCode, setVerificationCode] = useState(''); // 입력된 인증번호
const [isVerificationSent, setIsVerificationSent] = useState(false); // 인증번호 발송 여부
const [isVerificationSuccessful, setIsVerificationSuccessful] = useState(null); // 인증 성공 여부
// 인증번호 요청 함수
const handleVerificationRequest = () => {
// 서버에 인증번호 발송 요청을 보냄
axios.post('/send-one', { phoneNumber })
.then(response => {
console.log('인증번호 발송 성공:', response.data);
setIsVerificationSent(true); // 인증번호 발송 성공 시 입력 필드를 표시하기 위해 상태를 true로 설정
})
.catch(error => {
console.error('인증번호 발송 실패:', error);
});
};
// 인증번호 입력 값 업데이트 함수
const handleVerificationCodeChange = (event) => {
setVerificationCode(event.target.value); // 입력된 인증번호를 상태에 저장
};
// 인증번호 검증 요청 함수
const handleVerificationSubmit = () => {
// 서버에 입력된 인증번호 검증 요청을 보냄
axios.post('/verify-code', { phoneNumber, verificationCode })
.then(response => {
setIsVerificationSuccessful(response.data); // 서버의 응답에 따라 인증 성공 여부를 업데이트
if (response.data) {
alert('인증 성공!'); // 인증 성공 시 알림 표시
} else {
alert('인증 실패! 다시 시도해주세요.'); // 인증 실패 시 알림 표시
}
})
.catch(error => {
console.error('인증 실패:', error);
});
};
return (
<div>
{/* 휴대전화 번호 입력 및 인증번호 요청 버튼 */}
<div style={{ marginBottom: '30px' }}>
<div style={{ justifyContent: 'flex-start', display: 'flex' }}>휴대전화 번호</div>
<Input
id="phone"
placeholder="휴대전화 번호를 입력하세요"
value={phoneNumber}
onChange={(e) => setPhoneNumber(e.target.value)} // 입력된 전화번호를 상태에 저장
style={{ width: '80%' }}
/>
<Button
variant="contained"
color="primary"
onClick={handleVerificationRequest} // 인증번호 요청 버튼 클릭 시 호출
>
인증
</Button>
<br />
</div>
{/* 인증번호 입력 필드 및 확인 버튼, 인증번호 발송 후에만 표시됨 */}
{isVerificationSent && (
<div style={{ marginBottom: '30px' }}>
<div style={{ justifyContent: 'flex-start', display: 'flex' }}>인증번호 입력</div>
<Input
id="verification-code"
placeholder="인증번호를 입력하세요"
value={verificationCode}
onChange={handleVerificationCodeChange} // 입력된 인증번호를 상태에 저장
style={{ width: '80%' }}
/>
<Button
variant="contained"
color="primary"
onClick={handleVerificationSubmit} // 인증번호 확인 버튼 클릭 시 호출
>
확인
</Button>
</div>
)}
</div>
);
}
export default Card2;