혼자서 끄적끄적하고 있는 프로젝트의 회원가입 부분에 핸드폰 번호로
인증번호를 발송하는 기능이 있으면 좋을 것 같아서 구현하게 되었다.
문자 발송 API를 찾아보던 중
NAVER SMS API 는 한달에 50건 무료인 것을 확인하여 해당 API를 사용하기로 했다.
진행순서
1. https://www.ncloud.com/
네이버 클라우드 플랫폼 회원가입
2. 오른쪽 상단 [콘솔] 클릭
3. Products & Services 메뉴의
Simple & Easy Notification Service 클릭
4. Simple & Easy Notification Service -> Project -> 프로젝트 생성하기
서비스 Type - SMS
이름, 설명 입력 후 생성하기
서비스 ID 부분 열쇠모양 누르면
발급받은 OPEN API Key를 확인할 수 있다.
* 참고
serviceId = 프로젝트 -> 서비스 ID의 ID 값
secretKey = 프로젝트 > 서비스 ID의 Secret Key
accessKey = 네이버클라우드 플랫폼 - 마이페이지 -> 인증키 관리 -> 신규 API 인증키 생성 -> Access Key ID
[Backend]
SmsServiceImpl.java
@Service
@Transactional
public class SmsServiceImpl implements SmsService{
@Value("${sms.serviceId}")
private String serviceId;
@Value("${sms.accessKey}")
private String accessKey;
@Value("${sms.secretKey}")
private String secretKey;
public String sendSms(String recipientPhoneNumber, String content) throws Exception {
Long time = System.currentTimeMillis();
List<MessagesDto> messages = new ArrayList<>();
messages.add(new MessagesDto(recipientPhoneNumber, content));
SmsRequest smsRequest = new SmsRequest("SMS", "COMM", "국가코드(82)", "발신자 번호 입력", "제목없음", messages);
ObjectMapper objectMapper = new ObjectMapper();
String jsonBody = objectMapper.writeValueAsString(smsRequest);
String sig = makeSignature(time); //암호화
RestTemplate restTemplate = new RestTemplate();
URI uri = new URI("https://sens.apigw.ntruss.com/sms/v2/services/{serviceId}/messages");
uri = new URIBuilder(uri).build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
URL url = new URL("https://sens.apigw.ntruss.com/sms/v2/services/{serviceId}/messages");
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setUseCaches(false);
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty("content-type", "application/json");
con.setRequestProperty("x-ncp-apigw-timestamp", time.toString());
con.setRequestProperty("x-ncp-iam-access-key", this.accessKey);
con.setRequestProperty("x-ncp-apigw-signature-v2", sig);
con.setRequestMethod("POST");
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.write(jsonBody.getBytes());
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
BufferedReader br;
System.out.println(responseCode);
if(responseCode==202) { // 정상 호출
br = new BufferedReader(new InputStreamReader(con.getInputStream()));
} else { // 에러 발생
br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
}
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = br.readLine()) != null) {
response.append(inputLine);
}
br.close();
System.out.println(response.toString());
return response.toString();
}
public String makeSignature(Long time) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException, URISyntaxException {
String space = " ";
String newLine = "\n";
String method = "POST";
URI url = new URI("/sms/v2/services/"+ this.serviceId+"/messages");
String timestamp = time.toString();
String accessKey = this.accessKey;
String secretKey = this.secretKey;
String message = new StringBuilder()
.append(method)
.append(space)
.append(url)
.append(newLine)
.append(timestamp)
.append(newLine)
.append(accessKey)
.toString();
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(message.getBytes("UTF-8"));
String encodeBase64String = Base64.encodeBase64String(rawHmac);
return encodeBase64String;
}
SmsService.java
public interface SmsService {
public String sendSms(String recipientPhoneNumber, String content) throws Exception;
}
SmsController.java
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class SmsController {
@Autowired
private final SmsService smsService;
@PostMapping("/sms")
public ResponseEntity<?> sendSms(@RequestBody Request request) throws Exception {
String data = smsService.sendSms(request.getRecipientPhoneNumber(), request.getContent());
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(data);
return ResponseEntity.ok(node);
}
}
SmsRequest.java
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class SmsRequest {
private String type;
private String contentType;
private String countryCode;
private String from;
private String content;
private List<MessagesDto> messages;
}
Request.java
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class Request {
private String recipientPhoneNumber;
private String title;
private String content;
}
MessagesDto.java
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class MessagesDto {
private String to;
private String content;
}
[FrontEnd]
SmsDataService.js
import api from './api';
class SmsDataService {
sendSms(request) {
return api.post("/sms", request);
}
}
export default new SmsDataService();
Register.vue
generateRandomCode(n) {
let str = ''
for (let i = 0; i < n; i++) {
str += Math.floor(Math.random() * 10)
}
return str
},
sendSms() {
if(this.request.recipientPhoneNumber) {
this.isSend = true;
this.request.content = this.generateRandomCode(6)
console.log("this.request.content : " + this.request.content)
SmsDataService.sendSms(this.request)
this.errorMessage = false;
} else {
this.isSend = false;
this.errorMessage = true;
}
},
compareAuthNumber() {
if(this.request.content == this.inputAuthNumber) {
this.isSend = false;
this.requestAuthNumber = false;
this.accessMessage = true;
this.isCorrect = true;
} else console.log("인증번호 동일하지 않음")
}
application.properties
Postman 사용하여 테스트 해본 결과 :
정상적으로 요청이 보내지는 것을 확인했다.
- 화면 구현
핸드폰 번호 미입력 후 요청 버튼 클릭 시 번호를 입력해주세요 에러창 출력
휴대폰 번호 입력 후 인증번호 요청 누르면 -> 인증번호 입력창과 확인 버튼이 생긴다.
보낸 인증번호와 입력한 번호가 맞을 경우
입력창, 확인 버튼 사라지고,
'인증 완료되었습니다.' 알림창 출력
'Dev > Project' 카테고리의 다른 글
Spring Boot + Vue.js + JWT (0) | 2022.02.04 |
---|