이번 클래스 101 클론 프로젝트에서는 회원가입에 문자인증이 들어갑니다.
네이버 문자인증 서비스를 사용하며, 처음으로 OPEN API 를 적용해봤습니다.
from my_settings import (
serviceId,
AUTH_SECRET_KEY,
AUTH_ACCESS_KEY,
SMS_SEND_PHONE_NUMBER,
SECRET,
ALGORITHM,
)
#SMS 보내기
class SMSVerificationView(View):
def send_verification(self, phone, code):
SMS_URL = 'https://sens.apigw.ntruss.com/sms/v2/services/' + f'{serviceId}' + '/messages'
timestamp = str(int(time.time() * 1000))
secret_key = bytes(AUTH_SECRET_KEY, 'utf-8')
method = 'POST'
uri = '/sms/v2/services/' + f'{serviceId}' + '/messages'
message = method + ' ' + uri + '\n' + timestamp + '\n' + AUTH_ACCESS_KEY
message = bytes(message, 'utf-8')
# 알고리즘으로 암호화 후, base64로 인코딩
signingKey = base64.b64encode(
hmac.new(secret_key, message, digestmod=hashlib.sha256).digest())
headers = {
'Content-Type': 'application/json; charset=utf-8',
'x-ncp-apigw-timestamp': timestamp,
'x-ncp-iam-access-key': AUTH_ACCESS_KEY,
'x-ncp-apigw-signature-v2': signingKey,
}
body = {
'type': 'SMS',
'contentType': 'COMM',
'countryCode': '82',
'from': f'{SMS_SEND_PHONE_NUMBER}',
'content': f'인녕하세요. ac101 입니다. 인증번호 [{code}]를 입력해주세요.',
'messages': [
{
'to': phone
}
]
}
# body를 json으로 변환
encoded_data = json.dumps(body)
# post 메서드로 데이터를 보냄
res = requests.post(SMS_URL, headers=headers, data=encoded_data)
return HttpResponse(res.status_code)
def post(self, request):
try:
data = json.loads(request.body)
phone = data['phone']
code = str(randint(100000, 999999))
#update_or_creaete(조건, defaults = 생성할 데이터 값)
PhoneVerification.objects.update_or_create(
phone=phone,
defaults={
'phone': phone,
'code' : code
}
)
# phone, code 를 인자로 send_verification 메서드를 호출
self.send_verification(
phone=phone,
code=code
)
return JsonResponse({'message': 'SUCCESS'}, status=201)
except KeyError as e:
return JsonResponse({'message': f'KEY_ERROR: => {e}'}, status=400)
except ValueError as e:
return JsonResponse({'message': f'VALUE_ERROR: => {e}'}, status=400)
# 문자인증 확인과정
class SMSVerificationConfirmView(View):
def post(self, request):
try:
data = json.loads(request.body)
phone = data['phone']
verification_number = data['code']
if verification_number == PhoneVerification.objects.get(phone=phone).code:
if not User.objects.filter(number=phone).exists():
User.objects.create(number=phone)
return JsonResponse({'message': 'SUCCESS'}, status=200)
else:
return JsonResponse({'message': 'REGISTERED_NUMBER'}, status=401)
return JsonResponse({'message': 'INVALID_NUMBER'}, status=401)
except KeyError as e:
return JsonResponse({'message': f'KEY_ERROR: => {e}'}, status=400)
except ValueError as e:
return JsonResponse({'message': f'VALUE_ERROR: => {e}'}, status=400)
class SMSVerification 가 실행되면 post 메서드에서 랜덤코드를 생성하고 전화번호와 코드를 send_verification 메서드로 호출합니다. 그러면 send_verification 메서드는 네이버 클라우드 플랫폼에서 발급받은 인증키와 인코딩한 시크릿 키 등을 헤더에 담아 네이버 서버로 보냅니다. 서버는 키를 검증하고 유효시, SMS API를 호출하게 됩니다. 그리고 body의 데이터에 따라 문자를 보내줍니다.
문자를 보내면서 문자인증 db 에 전화번호와 인증코드를 저장하고, 클라이언트로 부터 넘어온 인증코드가 맞는지 확인하는 작업을 가집니다. 인증번호가 일치하고, 유저 db 에 데이터로 받은 전화번호가 없다면 유저db 에 번호를 저장합니다.
참고 : 네이버 API 가이드, 네이버 SMS API