ORM

Djangoのユーザー認証入門|ログイン・ログアウトの実装方法

Django ORM

Djangoのユーザー認証入門
ログイン・ログアウトの実装方法

Djangoの認証システムを使って、ログイン・ログアウト・アクセス制御を実装する方法を解説します。

こんな人向けの記事です

  • Djangoでログイン機能を実装したい人
  • 認証システムの仕組みを理解したい人
  • ビューのアクセス制御を行いたい人

Step 1Djangoの認証システム

Djangoには標準で認証システム(django.contrib.auth)が組み込まれています。ユーザーの認証、セッション管理、権限管理を提供します。

Python
# settings.py - 認証関連の設定
INSTALLED_APPS = [
    "django.contrib.auth",          # 認証フレームワーク
    "django.contrib.contenttypes",  # コンテンツタイプ(権限に必要)
    "django.contrib.sessions",      # セッション管理
    # ...
]

MIDDLEWARE = [
    "django.contrib.sessions.middleware.SessionMiddleware",       # セッション
    "django.contrib.auth.middleware.AuthenticationMiddleware",    # 認証
    # ...
]

# ログイン・ログアウト後のリダイレクト先
LOGIN_URL = "/login/"             # 未ログイン時のリダイレクト先
LOGIN_REDIRECT_URL = "/"          # ログイン成功後のリダイレクト先
LOGOUT_REDIRECT_URL = "/login/"   # ログアウト後のリダイレクト先

Step 2ログインの実装

authenticate()login()を使ってユーザー認証を行います。

Python
# views.py
from django.contrib.auth import authenticate, login
from django.shortcuts import render, redirect
from django.contrib import messages

def login_view(request):
    if request.method == "POST":
        username = request.POST["username"]
        password = request.POST["password"]

        # ユーザー認証(パスワードの検証)
        user = authenticate(request, username=username, password=password)

        if user is not None:
            # 認証成功 → ログイン(セッションにユーザー情報を保存)
            login(request, user)
            messages.success(request, f"ようこそ、{user.username}さん")

            # next パラメータがあればそのページへリダイレクト
            next_url = request.GET.get("next", "/")
            return redirect(next_url)
        else:
            # 認証失敗
            messages.error(request, "ユーザー名またはパスワードが正しくありません")

    return render(request, "auth/login.html")
HTML
<!-- templates/auth/login.html -->
<h1>ログイン</h1>

{% if messages %}
  {% for message in messages %}
    <div class="alert alert-{{ message.tags }}">{{ message }}</div>
  {% endfor %}
{% endif %}

<form method="post">
  {% csrf_token %}
  <div>
    <label>ユーザー名</label>
    <input type="text" name="username" required>
  </div>
  <div>
    <label>パスワード</label>
    <input type="password" name="password" required>
  </div>
  <button type="submit">ログイン</button>
</form>
Django標準のLoginViewを使う方法
上記のビューを自分で書く代わりに、DjangoのLoginViewを使うこともできます。
from django.contrib.auth.views import LoginView
path("login/", LoginView.as_view(template_name="auth/login.html"), name="login")

Step 3ログアウトの実装

Python
# views.py
from django.contrib.auth import logout

def logout_view(request):
    logout(request)  # セッションを破棄
    messages.info(request, "ログアウトしました")
    return redirect("login")

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("login/", views.login_view, name="login"),
    path("logout/", views.logout_view, name="logout"),
]
HTML
<!-- テンプレートでのログイン状態の表示 -->
{% if user.is_authenticated %}
  <p>{{ user.username }}さん、こんにちは</p>
  <a href="{% url 'logout' %}">ログアウト</a>
{% else %}
  <a href="{% url 'login' %}">ログイン</a>
{% endif %}

Step 4アクセス制御

ログインしていないユーザーからビューを保護する方法です。

Python
# 方法1: @login_required デコレータ(関数ビュー)
from django.contrib.auth.decorators import login_required

@login_required
def dashboard(request):
    # ログインしていないとLOGIN_URLにリダイレクト
    return render(request, "dashboard.html")

@login_required(login_url="/custom-login/")
def profile(request):
    # カスタムログインURLにリダイレクト
    return render(request, "profile.html")
Python
# 方法2: LoginRequiredMixin(クラスベースビュー)
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView, ListView

class DashboardView(LoginRequiredMixin, TemplateView):
    template_name = "dashboard.html"

class ArticleListView(LoginRequiredMixin, ListView):
    model = Article
    login_url = "/login/"  # オプション

# 方法3: 権限チェック
from django.contrib.auth.decorators import permission_required

@permission_required("app.add_article", raise_exception=True)
def create_article(request):
    # app.add_article 権限がないと403エラー
    pass

# 方法4: ビュー内でカスタムチェック
@login_required
def admin_dashboard(request):
    if not request.user.is_staff:
        messages.error(request, "管理者のみアクセスできます")
        return redirect("home")
    return render(request, "admin/dashboard.html")
LoginRequiredMixinの順番
クラスベースビューでLoginRequiredMixinを使う場合、必ず最初の親クラスとして指定してください。class MyView(LoginRequiredMixin, ListView)のように書きます。

Step 5ユーザー登録の実装

Python
# forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.password_validation import validate_password

class SignupForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput)
    password_confirm = forms.CharField(
        widget=forms.PasswordInput, label="パスワード(確認)"
    )

    class Meta:
        model = User
        fields = ["username", "email"]

    def clean_password(self):
        password = self.cleaned_data.get("password")
        validate_password(password)
        return password

    def clean(self):
        cleaned_data = super().clean()
        if cleaned_data.get("password") != cleaned_data.get("password_confirm"):
            raise forms.ValidationError("パスワードが一致しません")
        return cleaned_data

    def save(self, commit=True):
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password"])
        if commit:
            user.save()
        return user
Python
# views.py
from django.contrib.auth import login
from .forms import SignupForm

def signup_view(request):
    if request.method == "POST":
        form = SignupForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)  # 登録後に自動ログイン
            messages.success(request, "アカウントを作成しました")
            return redirect("home")
    else:
        form = SignupForm()

    return render(request, "auth/signup.html", {"form": form})

まとめ

  • authenticate()で認証し、login()でセッションに記録する
  • logout()でセッションを破棄してログアウトする
  • @login_requiredLoginRequiredMixinでアクセス制御する
  • テンプレートではuser.is_authenticatedでログイン状態を確認できる
  • set_password()でハッシュ化して保存し、check_password()で検証する