250326 TIL #627 SMS 인증 기능 구현

김춘복·2025년 3월 26일
0

TIL : Today I Learned

목록 보기
631/636

Today I Learned

SMS 비용을 줄이기 위해 국내 발송은 NHN cloud의 sms 서비스를 이용하기로 했다.


SMS 인증 기능 구현

  • 기존 SMS 발송 기능은 Twilio로 국내와 해외 발송 모두 구현
  • 하지만 비용의 대부분을 차지하는 국내 SMS 발송의의 경우 twilio는 건당 약 70원 정도 하기 때문에 누적 시 비용 부담이 있다.
  • 국내 SMS 발송의 경우 NHN Cloud의 SMS 서비스를 이용하면 약 건당 9.9원이므로 비용을 훨씬 줄일 수 있다.
  • 그래서 국가번호 +82만 NHN Cloud를 통해서 보내도록 구현을 시도해보았다.

NHNSMS 클래스

import axios, { AxiosInstance } from 'axios';

interface NHNSMSConfig {
  appKey: string;
  secretKey: string;
  sendNo: string;
  host: string;
  timeout: number;
  version: string;
  [key: string]: any;
}

// 환경변수 확인 과정
const NHN_CLOUD_SMS_API_KEY = env.NHN_CLOUD_SMS_API_KEY;
const NHN_CLOUD_SMS_SECRET_KEY = env.NHN_CLOUD_SMS_SECRET_KEY;
const NHN_CLOUD_SMS_SEND_NUMBER = env.NHN_CLOUD_SMS_SEND_NUMBER;

if (!NHN_CLOUD_SMS_API_KEY || !NHN_CLOUD_SMS_SECRET_KEY || !NHN_CLOUD_SMS_SEND_NUMBER) {
  throw new Error('NHN Cloud SMS Environments are invalid');
}

const defaultConfig: NHNSMSConfig = {
  appKey: NHN_CLOUD_SMS_API_KEY,
  secretKey: NHN_CLOUD_SMS_SECRET_KEY,
  sendNo: NHN_CLOUD_SMS_SEND_NUMBER,
  host: 'https://api-sms.cloud.toast.com',
  timeout: 1000 * 5, // 5초
  version: '3.0' // 2.3, 2.4, 3.0 버전을 지원
};

class NHNSMS{
  private config: NHNSMSConfig;
  private client: AxiosInstance;

  constructor(config: Partial<NHNSMSConfig> = {}) {
    this.config = Object.assign({}, defaultConfig, config);

    this.client = axios.create({
      baseURL: this.config.host,
      responseType: 'json',
      timeout: this.config.timeout,
    });

    this.client.defaults.headers.common['Content-Type'] = 'application/json;charset=UTF-8';
    this.client.defaults.headers.common['X-Secret-Key'] = this.config.secretKey;
  }
  
  async sendAuthSMS(country_code: string, phone: string, message: string): Promise<any> {
    const url = `${this.config.host}/sms/v${this.config.version}/appKeys/${this.config.appKey}/sender/auth/sms`;
    const sendNo = this.config.sendNo;

    try {
      // axios로 NHN API에 요청
      const response = await this.client.post(url, {
        body: message,
        sendNo: sendNo,
        recipientList: [
          {
            recipientNo: phone,
            countryCode: country_code,
          },
        ],
      });
      return response.data;
    } catch (error: any) {
      console.error('sendAuthSMS ERROR:', error);
      if (error.isAxiosError) {
        console.error('Axios Error Details:', error.response?.data);
      }
      throw error;
    }
  }
}
export default NHNSMS;

발송 API

// 지역번호 +82일 때 ...
// 랜덤 6자리 생성. 앞에 빈자리가 있으면 0으로 채움 ex) 002341
const authNum = String(Math.floor(Math.random() * 10 ** 6)).padStart(6, '0');
const phone = to.replace('+' + country_code, '').replace(/(^[^0])/, '0$1');
const smsClient = new NHNSMS();
const message = `SMS 인증 번호는 [${authNum}] 입니다`;
const result = await smsClient.sendAuthSMS(countryCode, phone, message);
if (result.header?.isSuccessful) { // ...
profile
Full-Stack Dev / Data Engineer

0개의 댓글