현재 진행 중인 프로젝트에 갑자기 문자서비스를 추가할 계획이라고 해서 급하게 문자 api 서비스 제공업체를 알아보기 시작했다. 문자서비스 제공업체들 대부분이 정액제로 운영이 되더라. 다행히 네이버 클라우드 플랫폼(NCP)에서도 문자서비스를 제공하고 있고, SMS 50건까지 무료라고 하니 테스하기에도 적당할 듯 해서 NCP SENS(Simple & Easy Notification Service) API를 이용하기로 했다.
인증키 생성
문자서비스 구현을 위해서 먼저 Access Key ID와 Secret Key, 서비스 ID가 필요했다.
로그인 후 콘솔 우측 상단의 계정Icon → 계정관리 → 인증키 관리로 이동해서 신규 API 인증키 생성을 클릭하면 API 인증키를 발급받을 수 있었다.
서비스 ID는 콘솔창에서 프로젝트를 생성하면 서비스 ID를 발급 받을 수 있다.
인증서비스 제작
NCP에서 API를 호출하기 위해서 header에 인증을 해줘야 했다. 네이버 API 호출 가이드를 따라서 하니 그닥 어렵지는 않았던 것 같다. (https://guide.ncloud-docs.com/docs/apigw-apigw-2-5)
헤더 구성은 총 네개로 구성된다.
headers: {
'Content-Type': 'application/json; charset=utf-8',
'x-ncp-iam-access-key': process.env.NCP_ACCESS_KEY,
'x-ncp-apigw-timestamp': Date.now().toString(),
'x-ncp-apigw-signature-v2': this.makeSignature(),
},
timestamp를 찍어줘야 하는데 문자타입으로 변환시켜 보내줘야 한다. (javascript 기준으로 Date.now().toString())
Access Key에는 API 인증키를 생성해서 받은 Access Key를 넣어준다.
Signature는 StringToSign을 생성하고 SecretKey로 HmacSHA256 알고리즘으로 암호화 한 후 Base64로 인코딩하면 된다고 한다.
Crypto-JS 패키지를 다운해야 하더라.
npm i crypto-js
npm i --save-dev @types/crypto-js
네이버 API 가이드에 예제 코드가 있어 작성하는 데는 어려움이 없었다.
private makeSignature(): string {
const space = ' ';
const newLine = '\n';
const method = 'POST';
const url = `/sms/v2/services/${process.env.NCP_SMS_SERVICE_ID}/messages`;
const timestamp = Date.now().toString();
const accessKey = process.env.NCP_ACCESS_KEY;
const secretKey = process.env.NCP_SECRET_KEY;
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, secretKey);
hmac.update(method);
hmac.update(space);
hmac.update(url);
hmac.update(newLine);
hmac.update(timestamp);
hmac.update(newLine);
hmac.update(accessKey);
const hash = hmac.finalize();
return hash.toString(CryptoJS.enc.Base64);
}
- HMAC : 비밀 메세지와 공유 메세지를 합친 후, 함수에 입력.
( 공유 메세지는 송신자와 수신자가 가지고 있어 메세지 보안 상승)
Base64로 인코딩하고, String으로 변환 후 리턴하였다.
예제 코드
private makeSignature(): string {
const space = ' ';
const newLine = '\n';
const method = 'POST';
const url = `/sms/v2/services/${process.env.NCP_SMS_SERVICE_ID}/messages`;
const timestamp = Date.now().toString();
const accessKey = process.env.NCP_ACCESS_KEY;
const secretKey = process.env.NCP_SECRET_KEY;
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, secretKey);
hmac.update(method);
hmac.update(space);
hmac.update(url);
hmac.update(newLine);
hmac.update(timestamp);
hmac.update(newLine);
hmac.update(accessKey);
const hash = hmac.finalize();
return hash.toString(CryptoJS.enc.Base64);
}
async sendSMS({ phoneNumber, content }: SMSType) {
const body = {
type: 'SMS',
contentType: 'COMM',
countryCode: '82',
from: process.env.PHONENUMBER, // 발신자 번호
content,
messages: [
{
to: phoneNumber, // 수신자 번호
},
],
};
console.log('body', body);
const options = {
headers: {
'Content-Type': 'application/json; charset=utf-8',
'x-ncp-iam-access-key': process.env.NCP_ACCESS_KEY,
'x-ncp-apigw-timestamp': Date.now().toString(),
'x-ncp-apigw-signature-v2': this.makeSignature(),
},
};
axios.post(process.env.NCP_URI, body, options).catch((err) => {
console.error(err.response.data);
throw new InternalServerErrorException();
});
return '전송 성공';
}
마치며
작성 후 Postman으로 테스트 하는데 에러가 발생해서 한참을 헤맸는데 알고보니 NCP에 발신번호를 등록하는 과정이 필요했다. 등록해야 가니 꼭 등록하고 테스트하길..
'Backend' 카테고리의 다른 글
[Spring Boot]GlobalExceptionHandler (Feat. @ControllerAdvice) (0) | 2024.02.21 |
---|---|
[Nest.js]핫 리로딩(Hot Reload) 설정 (0) | 2022.09.12 |
[Nest.js]Parsing error: cannot read file tsconfig.json (0) | 2022.02.09 |
[Nest.js] TypeError: (0 , cookie_parser_1.default) is not a function (0) | 2022.02.09 |