Django+HTML+MySQLでSMS認証ログインを実装する方法

はじめに

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の说明ページでは、以下の点に注意してください:

  1. テンプレート設定:SMSの内容にはテンプレートが必要です。6桁の認証コード之外的部分は事前に設定好的です。
  2. リクエストパラメータ:mobile(電話番号)とcontent(認証コード内容)を指定してリクエストを送信します。
  3. リクエスト方法: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送信機能を実装できます。

タグ: Django Python MySQL SMS認証 Web開発

6月11日 22:34 投稿