์์ ์ค์ธ project์์ ํ์๊ฐ์ ์ ํธ๋ํฐ ๋ฒํธ๋ฅผ ํตํ ๋ฌธ์์ธ์ฆ์ ๊ตฌํํ๊ณ ์ถ์๋ค.
googling์ ํตํด NAVER cloud ๊ฐ SMS API ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๊ฒ์ ํ์ธ, django์์ ์ฌ์ฉ์ ํธ๋ํฐ๋ฒํธ๋ฅผ ๋ฐ์ผ๋ฉด ์ธ์ฆ์ฝ๋๋ฅผ ๋ฐ๊ธํ์ฌ ncloud์ ๋ฌธ์ ์ ์ก ์์ฒญ์ ํ๊ณ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ๋ ์ธ์ฆ์ฝ๋๋ฅผ ํ์ธํ์ฌ "์น์ธ"์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ ๋ก์ง์ ๊ตฌํํ๋ค.
SMS Service ์ด์ฉ์ ์ํด ํ๋ซํผ์ ๊ฒ์ํ๋ค๊ฐ ๊ฐ์ฅ ์ ๋ ดํ๊ณ ์ฒซ ๊ฐ์ ์ 10๋ง ํฌ์ธํธ๋ฅผ ์ ๊ณตํ๋ naver cloud๋ฅผ ์ ํํ๋ค. Service๋ฅผ ์ด์ฉํ๊ธฐ ์ํด์ Access key์ secret key๋ฅผ ๋ฐ๊ธ๋ฐ์์ผ ํ๋๋ฐ ์ด ๋ฐฉ์์ naver cloud์์ ์น์ ํ๊ฒ ์๊ฐํ๊ณ ์๋ค.
Backend๊ฐ ๋ฐ๊ธํ ์ธ์ฆ์ฝ๋๋ฅผ ๊ฐ์ ์ ์ฒญ์๋ 5๋ถ ์ด๋ด์ Service์ ์ ์กํด์ผ ํ๋ค. Backend์์ ์ด๋ฅผ ์ํด TimeStampModel์ table์ ์์ฑ, "์ธ์ฆ์์ฒญ" ๋ฉ์์ง ์์ ์ ํด๋น phone number์ ์์ฑํ ์ธ์ฆ์ฝ๋๋ฅผ table์ ๋ด๋๋ค.
# user/models.py from random import randint import time import datetime import hmac import base64 import hashlib import requests import json from django.db import models from django.utils import timezone from model_utils.models import TimeStampedModel class SMSAuthRequest(TimeStampedModel): phone_number = models.CharField(verbose_name='ํด๋ํฐ ๋ฒํธ', primary_key=True, max_length=50) auth_number = models.IntegerField(verbose_name='์ธ์ฆ ๋ฒํธ') class Meta: db_table = 'sms_auth_requests' def save(self, *args, **kwargs): self.auth_number = randint(1000, 10000) super().save(*args, **kwargs) self.send_sms() # ์ธ์ฆ๋ฒํธ๊ฐ ๋ด๊ธด SMS๋ฅผ ์ ์ก def send_sms(self): service_id = '์๋น์คID' url = 'https://sens.apigw.ntruss.com' uri = '/sms/v2/services/' + service_id + '/messages' api_url = url + uri body = { "type": "SMS", "contentType": "COMM", "from": "{๋ฐ์ก ๋ฒํธ}", "content": "[ํ ์คํธ] ์ธ์ฆ ๋ฒํธ [{}]๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์.".format(self.auth_number), "messages":[{"to":self.phone_number}] } timeStamp = str(int(time.time() * 1000)) access_key = '{๋ฐ๊ธ๋ฐ์ access_key}' string_to_sign = "POST " + uri + "\n" + timeStamp + "\n" + access_key signature = self.make_signature(string_to_sign) headers = { "Content-Type": "application/json; charset=UTF-8", "x-ncp-apigw-timestamp": timeStamp, "x-ncp-iam-access-key": access_key, "x-ncp-apigw-signature-v2": signature } def make_signature(self, string): secret_key = bytes('{๋ฐ๊ธ๋ฐ์ ๋น๋ฐํค}', 'UTF-8') string = bytes(string, 'UTF-8') string_hmac = hmac.new(secret_key, string, digestmod=hashlib.sha256).digest() string_base64 = base64.b64encode(string_hmac).decode('UTF-8') return string_base64 @classmethod def check_auth_number(cls, p_num, c_num): time_limit = timezone.now() - datetime.timedelta(minutes=5) result = cls.objects.filter( phone_number=p_num, auth_number=c_num, modified__gte=time_limit ) if result: return True return False
์ฌ์ฉ์ ์์ฒญ์ ๋ํด ์ฒ๋ฆฌํ๋ View ๋ก์ง์ ์๋์ ๊ฐ๋ค
# user/views.py import re import jwt import json import bcrypt from rest_framework import status from rest_framework.response import Response from rest_framework.views import APIView class SMSCheckView(APIView): def post(self, request): try: phone_number = request.data['phone_number'] SMSAuthRequest.objects.update_or_create(phone_number=phone_number) return Response({'message': 'OK'}) except KeyError: return Response({'message': 'Bad Request'}, status=400) def get(self, request): try: phone_number = request.query_params['phone_number'] auth_number = request.query_params['auth_number'] result = SMSAuthRequest.check_auth_number(phone_number, auth_number) return Response({'message': 'OK', 'result': result}) except KeyError: return Response({'message': 'Bad Request'}, status=400)
์ฌ์ฉ์๊ฐ ์์ฒญ์ ํ๋ฉด ์๋์ฒ๋ผ table์ ์์ฒญ์์ ํธ๋ํฐ๋ฒํธ์ ๋ฐ๊ธํ ์ธ์ฆ์ฝ๋, timestamp๊ฐ ๋ด๊ธด๋ค.
๊ทธ ํ naver cloud SMS service์ ํด๋น ํธ๋ํฐ๋ฒํธ๋ก ์ธ์ฆ์ฝ๋๋ฅผ ๋ฌธ์์ ์ก ์์ฒญํ๊ณ ์ฌ์ฉ์๊ฐ ๋ฌธ์๋ฅผ ๋ฐ์ ์ต์ข ์ ์ผ๋ก ํธ๋ํฐ๋ฒํธ์ ์ธ์ฆ์ฝ๋๋ฅผ ๋ณด๋ด๋ฉด Backend๋ ์น์ธ์ฌ๋ถ๋ฅผ ๋ฆฌํด