はじめに
SMS認証によるログイン機能は、多くのWebアプリケーションで必要とされる重要な機能です。しかし、ネット上のチュートリアルは不完全であることが多く、SMSサービスの探し方がわからなかったり、実行できなかったりと 어려움을 겪较多います。今回は、DjangoとHTMLとMySQLだけを使用して、SMS認証ログインを実装する方法を詳しく解説します。
使用する技術スタック
- Django(PyCharm)
- HTML(PyCharm)
- MySQL(Navicat)
Vue.js、JavaScript、Redisは不要です。シンプルな構成で実装していきます。
SMS送信サービスの準備
まずはSMSを送信できるクラウドサービスが必要です。阿里雲のマーケットプレイスにあるSMSサービスがお勧めです。官方の阿里雲サーバーよりも費用が抑えられており、手続きも簡単です。
学習用途であれば、免费試用で5回、または3元で100回のSMS送信が可能です。
API情報の取得
サービスを購入または試用すると、AppCodeが発行されます。このAppCodeはAPIを使用するための重要な認証キーです。
APIの说明ページでは、以下の点に注意してください:
- テンプレート設定:SMSの内容にはテンプレートが必要です。6桁の認証コード之外的部分は事前に設定好的です。
- リクエストパラメータ:mobile(電話番号)とcontent(認証コード内容)を指定してリクエストを送信します。
- リクエスト方法:APIエンドポイントとHTTPメソッドを確認します。
テスト送信
管理画面上で電話番号を入力してテスト送信を行うことで、SMSを受け取れることを確認できます。このときのリクエスト情報が、ローカル環境での実装基础となります。
PythonでのSMS送信関数
阿里雲マーケットプレイス提供的APIリクエスト例をベースに、ローカルで呼び出せる関数を作成します。
import random
import urllib.parse
import urllib3
def send_sms(phone_number):
"""SMSを送信する関数"""
host = 'https://zwp.market.alicloudapi.com'
path = '/sms/sendv2'
method = 'GET'
appcode = 'あなたのAppCode'
# 6桁のランダム認証コードを生成
auth_code = str(random.randint(100000, 999999))
# メッセージ内容(テンプレートに従う)
message = '【スマートクラウド】您的验证码は' + auth_code + 'です。本人でない場合は無視してください'
# UTF-8でエンコード
encoded_message = urllib.parse.quote(message)
# クエリパラメータを作成
querys = 'mobile=' + phone_number + '&content=' + encoded_message
url = host + path + '?' + querys
# HTTPリクエストを送信
http = urllib3.PoolManager()
headers = {
'Authorization': 'APPCODE ' + appcode
}
response = http.request('GET', url, headers=headers)
result = response.data.decode('utf-8')
return auth_code
関数のポイント
- host:APIのエンドポイントURL
- appcode:自分のAppCodeに書き換える
- querys:電話番号とメッセージ内容を含む
- 戻り値:生成した認証コードを返す
テンプレートについて
SMSのテンプレートは管理画面から申請できます。 templatesの【】で囲まれた部分是署名であり、後の内容が本文です。テンプレートは審査通过的必要があります。
Djangoプロジェクトの実装
models.py
from django.db import models
class Member(models.Model):
"""会員モデル"""
phone_number = models.CharField(max_length=11, unique=True)
is_verified = models.BooleanField(default=False)
verification_code = models.CharField(max_length=6, blank=True, null=True)
acquire_time = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.phone_number
モデルを作成したら、makemigrationsとmigrateを実行してデータベースに反映させます。
views.py
import datetime
import random
import urllib.parse
import urllib3
from django.shortcuts import render, HttpResponse
from .models import Member
def send_verification_code(request):
"""認証コード送信ビュー"""
if request.method == "POST":
phone = request.POST.get('phone_number')
try:
member = Member.objects.get(phone_number=phone)
# 認証コードを生成してSMSを送信
code = generate_sms_code(phone)
member.verification_code = code
member.acquire_time = datetime.datetime.now()
member.save()
return HttpResponse("認証コードを送信しました")
except Member.DoesNotExist:
return HttpResponse("登録されていない電話番号です")
return render(request, 'send_code.html')
def verify_login(request):
"""ログイン認証ビュー"""
if request.method == "POST":
phone = request.POST.get('phone_number')
input_code = request.POST.get('verification_code')
try:
member = Member.objects.get(phone_number=phone)
# 時間の比較(5分=300秒以内)
now = datetime.datetime.now()
time_diff = (now - member.acquire_time).total_seconds()
if time_diff > 300:
return HttpResponse("認証コードが期限切れです")
if member.verification_code == input_code:
member.is_verified = True
member.save()
return HttpResponse("ログイン成功")
return HttpResponse("認証コードが間違っています")
except Member.DoesNotExist:
return HttpResponse("登録されていない電話番号です")
return render(request, 'verify_login.html')
def generate_sms_code(phone):
"""SMS送信と認証コード生成"""
host = 'https://zwp.market.alicloudapi.com'
path = '/sms/sendv2'
appcode = 'あなたのAppCode'
code = str(random.randint(100000, 999999))
message = '【スマートクラウド】您的验证码は' + code + 'です。'
encoded_msg = urllib.parse.quote(message)
querys = 'mobile=' + phone + '&content=' + encoded_msg
url = host + path + '?' + querys
http = urllib3.PoolManager()
headers = {'Authorization': 'APPCODE ' + appcode}
http.request('GET', url, headers=headers)
return code
HTMLテンプレート
認証コード送信ページ(send_code.html):
<html>
<head>
<meta charset="UTF-8">
<title>認証コード送信</title>
</head>
<body>
<form method="post" action="">
{% csrf_token %}
<label for="phone_number">電話番号:</label>
<input type="text" id="phone_number" name="phone_number" required><br>
<input type="submit" value="送信">
</form>
</body>
</html>
ログイン認証ページ(verify_login.html):
<html>
<head>
<meta charset="UTF-8">
<title>ログイン認証</title>
</head>
<body>
<form method="post" action="">
{% csrf_token %}
<label for="phone_number">電話番号:</label>
<input type="text" id="phone_number" name="phone_number" required><br>
<label for="verification_code">認証コード:</label>
<input type="text" id="verification_code" name="verification_code" required><br>
<input type="submit" value="認証">
</form>
</body>
</html>
urls.py
プロジェクトのurls.py:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('authapp.urls')),
]
アプリケーションのurls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.send_verification_code, name='send_code'),
path('verify/', views.verify_login, name='verify_login'),
]
動作確認
開発サーバーを起動して以下のURLにアクセスします:
- 認証コード送信:http://127.0.0.1:8000/
- ログイン認証:http://127.0.0.1:8000/verify/
電話番号を入力して認証コードを送信すると、データベースに認証碼と時刻が保存されます。その後、受信した認証碼を入力してログインを行います。
日付処理の注意点
datetimeオブジェクトの比較を行う際、タイムゾーンの考慮が必要です。UTCとローカル時間の差異に注意が必要です。
まとめ
今回はDjangoとHTMLとMySQLを使用してSMS認証ログインを実装しました。特別なライブラリを使わずに、標準的なPythonライブラリのみで実現できます。阿里雲のマーケットプレイスを利用すれば、低コストでSMS送信機能を実装できます。