目次- 認証
- 認証コード送信API
- 公式SMS SDKのカスタマイズ
認証
- データベーステーブルを設計 2. 要求に応じてAPIを設計 3. コードを記述してAPIの機能を実装
-
ユーザー名、メールアドレス、電話番号によるパスワードログイン
- ユーザー名とパスワードを入力し、ログインAPIにPOSTリクエストを送る
- 検証が成功した場合、トークンを発行する
-
電話番号と認証コードによるログイン
- 電話番号を入力
- 「認証コードを送信」ボタンをクリックし、認証コード送信APIにGETリクエストを送る
- 認証コードを入力し、電話番号と認証コードによるログインAPIにPOSTリクエストを送る
- Djangoキャッシュから認証コードを取り出し検証を行い、検証が成功するとトークンを発行する
''' # ...\luffyapi\luffyapi\apps\user\urls.py ... urlpatterns = [ ..., path('code/login/', views.CodeLoginAPIView.as_view()), # 電話番号 + 認証コードログインAPI ] # ...\luffyapi\luffyapi\apps\user\views.py from rest_framework_jwt.views import JSONWebTokenAPIView from . import my_serializers class CodeLoginAPIView(JSONWebTokenAPIView): serializer_class = my_serializers.CodeLoginSerializer # ...\luffyapi\luffyapi\apps\user\my_serializers.py ... from rest_framework import serializers class CodeLoginSerializer(serializers.Serializer): code = serializers.CharField(min_length=6, max_length=6) mobile = serializers.CharField(min_length=11, max_length=11) def validate(self, attrs): mobile = attrs.get('mobile') code = attrs.get('code') if not code.isdigit(): # 認証コードが数字のみかチェックし、それ以外はエラー raise serializers.ValidationError('認証コードは数字のみでなければなりません') cache_code = cache.get(settings.CODE_CACHE_FORMAT % mobile) # サーバー側のキャッシュから認証コードを取得 if code != cache_code: raise serializers.ValidationError('認証コードが間違っています') try: user = models.User.objects.get(mobile=mobile, is_active=True) except: raise serializers.ValidationError('この電話番号は登録されていません') payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) self.object = {'token': token, 'user': user} cache.delete(settings.CODE_CACHE_FORMAT % mobile) # 電話番号 + 認証コードログイン成功後にDjangoキャッシュ内の認証コードを削除 return attrs '''
認証コード送信API
- 認証コードを生成
- 腾讯云に認証コードを送信
- 腾讯云のSMS APIドキュメントを参照
- 公式提供されたSMS SDKをカスタマイズ
- SMS送信成功後に生成された認証コードをDjangoキャッシュに保存
'''
# ...\luffyapi\luffyapi\apps\user\urls.py
...
urlpatterns = [
...
path('code/send/', views.SendSmsAPIView.as_view()), # 認証コード送信API
]
# ...\luffyapi\luffyapi\apps\user\views.py
...
from luffyapi.libs.sms_sdk import send_sms
from luffyapi.utils.sms_code import generate_code
from django.core.cache import cache
from django.conf import settings
from rest_framework.response import Response
class SendSmsAPIView(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, *args, **kwargs): # GETリクエストの処理効率はPOSTより高い
mobile = request.query_params.get('mobile')
if not mobile:
return Response(data={'code': 1001, 'detail': 'mobileフィールドが必要です'}, status=400)
if not re.match(r'^1[3-9][0-9]{9}$', mobile):
return Response(data={'code': 1002, 'detail': '電話番号の形式が誤っています'}, status=400)
code = generate_code()
res = send_sms([mobile, ], code, settings.CODE_EXP // 60) # 認証コードの有効時間は分単位
if not res:
return Response(data={'code': 1003, 'detail': '認証コード送信失敗'}, status=500)
cache.set(settings.CODE_CACHE_FORMAT % mobile, code, settings.CODE_EXP) # Djangoキャッシュの有効時間は秒単位
return Response(data={'code': 0, 'msg': '認証コード送信成功', })
# ...\luffyapi\luffyapi\utils\sms_code.py
# 6桁のランダムな数字の認証コードを生成
def generate_code():
import random
lt = []
for i in range(10):
lt.append(str(i))
rand_lt = random.sample(lt, 6)
code = ''.join(rand_lt)
return code
# ...\luffyapi\luffyapi\settings\const_settings.py
...
CODE_CACHE_FORMAT = 'code_cache_%s' # 認証コードキャッシュキー
CODE_EXP = 30000 # 認証コード有効時間
'''
公式提供されたSMS SDKのカスタマイズ
'''
# ...\luffyapi\luffyapi\libs\sms_sdk\settings.py
... # 認証コード送信メソッドを呼び出すために必要な固定設定
# ...\luffyapi\luffyapi\libs\sms_sdk\single_send.py
from qcloudsms_py import SmsSingleSender
from .settings import TEMPLATE_ID, SMS_SIGN, APPID, APPKEY
from luffyapi.utils.my_logging import logger
# 認証コードを送信
def send_sms(phone_num_lt, code, exp):
try:
sender = SmsSingleSender(APPID, APPKEY)
response = sender.send_with_param(86, phone_num_lt[0], TEMPLATE_ID, (code, exp), sign=SMS_SIGN, extend="", ext="")
# print(response) # {'result': 0, 'errmsg': 'OK', 'ext': '', 'sid': '8:rIcypgwqRVSqRCVVJ0e20200113', 'fee': 1}
if response.get('result') != 0:
logger.error('認証コード送信失敗, "code": %s, "detail": %s' % (response.get('result'), response.get('errmsg')))
return False
return True
except Exception as e:
logger.error('コード実行異常, "detail": %s' % e)
# ...\luffyapi\luffyapi\libs\sms_sdk\__init__.py
from .single_send import send_sms # パッケージ向けカスタマイズ
'''