- Django に認証機能を実装したい
- 認証状況ごとに表示するページを変えたい
Djangoでは標準でログイン・ログアウト関連のモジュールが実装されています。
そのため、簡単な操作でログイン・ログアウト機能を導入することが可能です。
本記事ではログイン・ログアウト機能の実装方法に加えて、訪問者のログイン状態に応じて見せるページに変化をつける方法なども解説します。
Djangoで認証を実装するための3つの方法
以下の3種類の実装方法があります。
- Djangoデフォルトの認証システム
- カスタム認証バックエンド
- サードパーティの認証アプリ
それぞれの違いも踏まえて、実装方法を解説します。
Djangoデフォルトの認証システムを使った方法
標準で搭載されている django.contrib.auth アプリを使う方法です。
ログイン、ログアウト、パスワード変更、パスワードリセットなどのビューが搭載されています。
実装方法を説明します。
settings.py の INSTALLED_APPS にdjango.contrib.auth があるか確認してください。
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
デフォルトでは入力されていると思いますが、念のため。これがないとDjango標準の認証システムが使えません。
続いて、urls.pyに以下のパスを追加します。
from django.contrib.auth.views import LoginView, LogoutView
from django.urls import path
urlpatterns = [
path("login/", LoginView.as_view(), name="login"),
path("logout/", LogoutView.as_view(), name="logout"),
]
これで /login/ にアクセスするとログインViewに遷移するようになりました。
ログインページの作成がまだなので、ログインページ用の html テンプレートを作成していきましょう。保存場所は registration/login.html です。
{% extends "base.html" %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
{% endblock %}
さらにもろもろのリダイレクト先をsettings.pyに設定します。
# 認証リダイレクト設定
LOGIN_URL = "login" # LOGINが必要なビューにアクセスがあった場合の遷移先
LOGIN_REDIRECT_URL = "home" # LOGIN後のリダイレクト先
LOGOUT_REDIRECT_URL = "home" # LOGOUT後のリダイレクト先
これにより、ログインに成功すると urls.py の path として name=”home” を設定したビューにリダイレクトされるようになります。
カスタム認証バックエンド
カスタム認証バックエンドとは、認証方法としてユーザー名やパスワード以外の要素を加えるための方法です。
前提として、Django標準認証の設定を終わらせてください。
まずは以下のような backends.py ファイルを用意します。
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
if user.check_password(password):
return user
def get_user(self, user_id):
UserModel = get_user_model()
try:
return UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
上記の例では、Emailによる認証を追加しました。
ファイルの格納先は特に決まりはないですが、一般的にはアプリケーションのルートディレクトリに配置されることが多いです。
myproject/
├── myproject/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── myapp/
│ ├── __init__.py
│ ├── backends.py
│ ├── models.py
│ ├── views.py
│ ├── urls.py
│ └── ...
└── manage.py
最後に settings.py で、新しく作成した認証バックエンドを以下のように追加します。
AUTHENTICATION_BACKENDS = ["path.to.backends.EmailBackend"]
サードパーティの認証アプリ
Django 非公式アプリを使った方法です。
サードパーティアプリとして有名な django-allauth を例に挙げて解説します。
まずはライブラリのインストールから行います。
# pipを使った場合
pip install django-allauth
# poetryを使った場合
poetry install django-allauth
続いて settings.py 周りの設定です。
INSTALLED_APPS = [
"django.contrib.sites",
"allauth",
"allauth.account",
"allauth.socialaccount",
# "allauth.socialaccount.providers.google", # Googleのような特定のプロバイダーを有効にする場合
]
AUTHENTICATION_BACKENDS = [
"allauth.account.auth_backends.AuthenticationBackend",
]
SITE_ID = 1
サイトフレームワーク (django.contrib.sites) も有効にする必要があります。
django-allauth を使う場合には二つ以上のサイトオブジェクトを扱う可能性があるので、あえて SITE_ID を定義しています。(通常は SITE_ID=1 なのですが、あえて定義することはない)
さらに settings.py 内の設定を行います。
例えばメールアドレスによる認証を行う場合には、以下のようになります。
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_UNIQUE_EMAIL = True
最後に urls.py の設定です。
from django.urls import include, path
urlpatterns = [
path("accounts/", include("allauth.urls")),
]
以上で django-allauth が提供する全ての認証ビュー(ログイン、ログアウト、パスワード変更、ソーシャルアカウントの接続など)が使えるようになります。
認証状況ごとに表示するページを変える方法
ここまでの解説で認証の実装ができるようになりました。
さらにログインしているかどうかで表示させるページを変えたい場合、次のような方法があります。
- ビューへのアクセス制限
- ビューでの制御
- テンプレートでの制御
それぞれ解説します。
ビューへのアクセス制限
ログアウト状態だとアクセスを許さないためには、2つの方法が用意されています。
- @login_required: 関数ベースビューの場合
- LoginRequiredMixin: クラスベースビューの場合
まずは、関数ベースビューの場合のサンプルコードです。
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
@login_required
def my_view(request):
return HttpResponse("This is a protected view.")
@login_required というデコレーターをつけることで、my_viewというビューにはログインしたユーザー以外アクセスできなくなります。
クラスベースビューの場合には次のようになります。
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class MyView(LoginRequiredMixin, TemplateView):
template_name = "my_template.html"
アクセス制限をかけたいビューに対して、LoginRequiredMixin クラスを継承します。
継承の際には一番左に記載する必要があるのでご注意ください。
ビューでの制御
ビュー内で認証の有無に応じた処理パターンを分岐させるには、 is_authenticated を使って状態を判断します。
まずは関数ベースの場合です。
def my_view(request):
if request.user.is_authenticated:
# 認証済みユーザー向けの処理
else:
# 未認証ユーザー向けの処理
クラスベースの場合は次のようになります。
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request, *args, **kwargs):
if request.user.is_authenticated:
return HttpResponse("You are authenticated")
else:
return HttpResponse("You are not authenticated")
基本的な考え方はどちらも同じです。
テンプレートでの制御
ビューではなく、HTMLテンプレート上で制御する方法もあります。
{% if user.is_authenticated %}
<!-- 認証済みユーザー向けの内容 -->
{% else %}
<!-- 未認証ユーザー向けの内容 -->
{% endif %}
こちらはif文で単純に条件分岐させる形になります。
コメント