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 LoginViewpath("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 userPython
# 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_requiredやLoginRequiredMixinでアクセス制御する- テンプレートでは
user.is_authenticatedでログイン状態を確認できる set_password()でハッシュ化して保存し、check_password()で検証する