2024年12月17日火曜日

メール認証付きユーザー登録の流れ

 Djangoでユーザー登録をメール承認(認証)付きにするのは多少の設定が必要ですが、Djangoが提供する機能を活用すれば、それほど大変ではありません。以下に、ステップごとに分解して説明します。


1. メール認証付きユーザー登録の流れ

  1. ユーザーがフォームで登録
    • 仮登録の状態でユーザーをデータベースに保存。
  2. メールを送信
    • ユーザーの入力したメールアドレス宛に認証用のリンクを送信。
  3. ユーザーがリンクをクリック
    • 認証リンクにアクセスした際、アカウントを有効化。
  4. 有効化されたアカウントでログイン可能に

2. 実装手順

2.1 仮登録用のモデルフィールドを追加

デフォルトのユーザーモデルには「有効/無効」を管理するフィールドがないため、is_active フィールドを利用します。

  • 新規登録時にデフォルトで is_active=False に設定し、メール認証後に True に変更します。

forms.py (変更なし)

上記で作成した CustomUserCreationForm をそのまま使用します。


2.2 認証トークン生成と検証

Djangoの signing モジュールを利用して、メール認証用のトークンを生成します。

認証トークン生成ヘルパー

utils.py を新規作成します。

python
from django.contrib.auth.tokens import default_token_generator from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.encoding import force_bytes, force_str from django.contrib.auth.models import User # トークン生成 def generate_email_verification_token(user): return default_token_generator.make_token(user) # トークンの検証 def verify_email_token(uidb64, token): try: uid = force_str(urlsafe_base64_decode(uidb64)) user = User.objects.get(pk=uid) except (TypeError, ValueError, OverflowError, User.DoesNotExist): return None if default_token_generator.check_token(user, token): return user return None

2.3 メール送信ビューの作成

Djangoの send_mail を使ってメールを送信します。

views.py

python
from django.shortcuts import render, redirect from django.contrib.auth import login from django.core.mail import send_mail from django.template.loader import render_to_string from django.utils.http import urlsafe_base64_encode from django.utils.encoding import force_bytes from django.contrib.sites.shortcuts import get_current_site from .forms import CustomUserCreationForm from .utils import generate_email_verification_token def register(request): if request.method == "POST": form = CustomUserCreationForm(request.POST) if form.is_valid(): user = form.save(commit=False) user.is_active = False # 仮登録 user.save() # メール送信 current_site = get_current_site(request) subject = "Activate Your Account" message = render_to_string("email_verification.html", { "user": user, "domain": current_site.domain, "uid": urlsafe_base64_encode(force_bytes(user.pk)), "token": generate_email_verification_token(user), }) send_mail(subject, message, "no-reply@example.com", [user.email]) return render(request, "email_sent.html") else: form = CustomUserCreationForm() return render(request, "register.html", {"form": form})

2.4 認証リンクのビューを作成

ユーザーがメールのリンクをクリックすると、アカウントが有効化されます。

views.py

python
from django.http import HttpResponse from django.contrib.auth.models import User from .utils import verify_email_token def activate_account(request, uidb64, token): user = verify_email_token(uidb64, token) if user is not None: user.is_active = True user.save() return HttpResponse("Your account has been activated! You can now log in.") else: return HttpResponse("Activation link is invalid!")

2.5 URLの設定

urls.py に登録用と有効化用のURLを追加します。

python
from django.urls import path from .views import register, activate_account urlpatterns = [ path('register/', register, name='register'), path('activate/<str:uidb64>/<str:token>/', activate_account, name='activate'), ]

2.6 認証メールテンプレート

email_verification.html

html
Hi {{ user.username }}, Please click the link below to verify your email address and activate your account: http://{{ domain }}{% url 'activate' uid=uid token=token %} Thank you!

2.7 メール送信設定

settings.py にメール送信設定を追加します。

python
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.example.com' EMAIL_PORT = 587 EMAIL_USE_TLS = True EMAIL_HOST_USER = 'your_email@example.com' EMAIL_HOST_PASSWORD = 'your_password' DEFAULT_FROM_EMAIL = 'no-reply@example.com'

3. テストとデバッグ

  1. ローカル環境でテストする場合は、console.EmailBackend を使用すると、メールがコンソールに出力されます。
    python
    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
  2. トークン生成やデコードでエラーが出た場合は、例外を確認してください。

4. メリットと応用

  • 安全性向上: メール確認を必須にすることで、無効なユーザー登録を防ぎます。
  • 通知機能と統合: この仕組みを活用して、パスワードリセットや重要な通知機能にも応用できます。

これで、Djangoでメール認証付きユーザー登録を実現できます!不明点や追加のカスタマイズがあれば、教えてください。