NAVER CLOUD PlATFORM[SENS API] - 네이버 문자 인증

하복치·2023년 4월 24일

PYTHON

목록 보기
1/5

👉 NAVER CLOUD PlATFORM

  • 네이버 클라우드 가입 후 콘솔에서 아래 메뉴(Simple & Easy Notification Service) 클릭한다.

  • 가장 먼저 프로젝트를 생성한다.

  • 필수 항목을 모두 작성한 후 생성하기 버튼을 클릭한다.

  • SMS Calling Number에서 발신번호를 등록한다.

  • 발신번호 등록이 완료되면 마이페이지-인증키 관리 메뉴로 이동하여 신규 API 인증키를 발급받는다.

  • API 인증키 생성이 완료되면 API 권한 설정에 사용하는 ip 주소를 입력 후 추가 > 저장한다.

  • 프로젝트 탭에서 서비스 ID를 누르면 서비스 ID를 확인할 수 있다.

  • 콘솔에서의 설정이 모두 완료되면 API 가이드에 따라 로직을 작성한다.
    👉 SMS API 가이드

SENS API 기본 설정

SMS_API_KEY, SMS_API_SECRET, SERVICE_ID, FROM_PHONE_NUMBER 등 보안과 관련된 정보는 config.py에 넣어 사용한다.

# config.py
SMS_API_KEY = 'string'
SMS_API_SECRET = 'string'
SMS_SERVICE_ID = 'string'
SMS_SENDER_NUMBER  = 'string'

Signature 생성

def	make_signature(timestamp):
	secret_key = bytes(SMS_API_SECRET, 'UTF-8')
	method = "POST"
	uri = f'/sms/v2/services/{SERVICE_ID}/messages'
	message = method + " " + uri + "\n" + timestamp + "\n" + SMS_API_KEY
	message = bytes(message, 'UTF-8')
	return base64.b64encode(hmac.new(secret_key, message, digestmod=hashlib.sha256).digest()) 

SENS API SMS 발송

def send_sms(phone_number, cert_code):
    timestamp = str(int(time.time() * 1000))
    signature = make_signature(timestamp)
    headers = {
        'Content-Type': 'application/json; charset=utf-8',
        'x-ncp-apigw-timestamp': timestamp,
        'x-ncp-iam-access-key': SMS_API_KEY,
        'x-ncp-apigw-signature-v2': signature
    }
    body = {
        "type":'sms',
        "contentType":"COMM",
        "countryCode":'82',
        "from":FROM_PHONE_NUMBER,
        "content": "[골리단길] 본인인증",
        "messages":[
            {
                "to": phone_number,
                "content": f'[골리단길] 본인 확인을 위해 인증번호[{cert_code}]를 입력해 주세요.'
            }
        ]
        }
    SMS_URL = f'https://sens.apigw.ntruss.com/sms/v2/services/{SERVICE_ID}/messages'
    response = requests.post(SMS_URL, headers=headers, json=body)
    return response.json()

인증번호 생성

def generate_otp(phone_number, otp_create_time):
  otp = str(randint(100000, 999999))
  session[f'otp_{phone_number}'] = otp  # 세션에 인증번호 저장
  session[f'time_{phone_number}'] = otp_create_time  # 인증번호 생성 시간 저장
  return otp

인증번호 SMS 보내기

@bp.route('/sendOtp', methods=['POST'])
def send_otp():
    phone_number = request.get_json(force=True)['phone']
    otp_create_time = request.get_json(force=True)['createTime']
    
    # 휴대폰 번호 중복 체크
    user = User.query.filter_by(phone = phone_number).first() 
    
    if user: 
        response={
        'resultCode': 409,
        'resultDesc': "Conflict",
        'resultMsg': "이미 가입된 번호입니다."
        }
        return Response(response=json.dumps(response), status=409, mimetype="application/json")
    else: 
        # 인증 코드 생성 함수 호출
        otp = generate_otp(phone_number, otp_create_time)

        # SMS 발송 함수 호출
        result = send_sms(phone_number, otp)  
        
        if result['statusCode'] == '202':
            response={
                'resultCode': 200,
                'resultDesc': "Success",
                'resultMsg': "문자가 발송되었습니다."
            }
            return Response(response=json.dumps(response), status=200, mimetype="application/json")
        else: 
            response={
                'resultCode': 401,
                'resultDesc': "Unauthorized",
                'resultMsg': "문자 발송에 실패했습니다."
            }
            return Response(response=json.dumps(response), status=401, mimetype="application/json")

인증번호 검증

@bp.route('/verifyOtp', methods=['POST'])
def verify_otp():
    otp = request.get_json(force=True)['otp'] 
    phone = request.get_json(force=True)['phone']  

    session_otp = session.get(f'otp_{phone}')  # 세션에 저장된 인증번호 가져오기
    session_time = session.get(f'time_{phone}')  # 세션에 저장된 생성 시간 가져오기

    # 세션에 인증번호와 생성 시간이 저장되어 있지 않은 경우
    if not session_otp or not session_time:
        response={
            'resultCode': 404,
            'resultDesc': "Not Found",
            'resultMsg': "해당 데이터가 존재하지 않습니다."
            }
        return Response(response=json.dumps(response), status=404, mimetype="application/json")
    
    # 시간이 만료된 경우
    if time.time() - session_time > 180:
    	# 세션에서 인증번호와 생성 시간을 삭제
        session.pop(f'otp_{phone}')  
        session.pop(f'time_{phone}')
        
        response={
            'resultCode': 401,
            'resultDesc': "Unauthorized",
            'resultMsg': "인증번호 인증 시간이 만료되었습니다."
            }
        return Response(response=json.dumps(response), status=401, mimetype="application/json")
    
    # 검증에 성공한 경우
    if otp == session_otp:
    	# 세션에서 인증번호와 생성 시간을 삭제
        session.pop(f'otp_{phone}')  
        session.pop(f'time_{phone}')
        
        response={
                'resultCode': 200,
                'resultDesc': "Success",
                'resultMsg': "인증이 성공적으로 완료되었습니다."
                }
        return Response(response=json.dumps(response), status=200, mimetype="application/json")
    else:
        response={
            'resultCode': 401,
            'resultDesc': "Unauthorized",
            'resultMsg': "인증번호가 일치하지 않습니다."
            }
        return Response(response=json.dumps(response), status=401, mimetype="application/json")
  • 문자 메시지 전송 성공

5개의 댓글

comment-user-thumbnail
2024년 4월 18일

혹시 메시지 결과 조회도 해보셨나요?

1개의 답글
comment-user-thumbnail
2024년 8월 16일

안녕하세요 ! 검증 하시는데 비용은 얼마나 나오셨을까요?

1개의 답글