【Django】ログイン機能の実装

既存システムからDjangoへのリプレースで、ログイン機能をどう実装するかを検討して、実装した時のメモ。

0.事前検討

(前提)

  • 既存システムDBには、既にID、パスワードソルト、パスワードハッシュ値がある。
  • 既存ユーザーには、ログイン方法の変更の通知はできる。

(方針)

  • この際、IDをメールアドレスに変更する。
  • なるべく、Djangoのフレームに乗っ取る形で実装する。
  • パスワードも再設定が可能なので、DjangoのUserモデル認証に切り替える。
  • 将来は、メールベースの二段階認証にする。

(参考ページ)

Djangoの認証システムを使用する

1.【ログイン】LoginViewで実装(1)

ログイン部分については、LoginViewを使用して実装する。

LoginView

基にしたVisual Studio のサンプルが、admin機能で利用しているので、利用者向けのログイン機能を追加する。

1-1)forms.py:ログインフォームの定義

forms.pyにユーザー用のログインフォームを定義する。Visual Studio のサンプルで既に定義されていたので、それをコピーして修正した。

変更点としては、usernameをメールアドレスで入力させるようにする。Userモデルにはusernameのほかにもemailも持っているがとりあえず。

class UserAuthenticationForm(AuthenticationForm):
    """Authentication for User Login."""
    username = forms.CharField(max_length=254,
                               widget=forms.EmailInput({
                                  'class': 'form-control',
                                  'placeholder': 'Email アドレス'}))
    password = forms.CharField(label=_("Password"),
                               widget=forms.PasswordInput({
                                   'class': 'form-control',
                                   'placeholder':'パスワード'}))

基底のAutheticationFormについては、以下を参照した。

class AuthenticationForm 

(GitHub)django.contrib.auth.forms.py

※今回は、従来のDBを使ったりとかしてカスタマイズすることも可能だとは思うが、手抜きで行くことに。

1-2)template:ログインページの定義

app/login.htmlというファイルで、テンプレートを作成。内容は、LoginViewを参考に。

1-3)url.pyの定義

urlpatternsに、ログインとログアウトを追加。

 :
from django.contrib.auth.views import LoginView, LogoutView
from app import forms, views
 :
urlpatterns = [
   :
    path('login/',
         LoginView.as_view
         (
             template_name='app/login.html',
             authentication_form=forms.UserAuthenticationForm,
             extra_context=
             {
                 'title': 'Login',
             },
         ),
         name='login'),
    path('logout/', LogoutView.as_view(next_page='/'), name='logout'),
   :
]
 :

1-4)setting.pyの定義

ログイン後の最初のページを「LOGIN_REDIRECT_URL」で定義する。

LOGIN_REDIRECT_URL

2.【ログイン】LoginViewで実装(2)

(1)では、Userのusernameにメールアドレスを入れるという強引な方法にしたが、ユーザー名も使いたい場合は、認証でUser.emailをチェックするように修正する。

Django の認証方法のカスタマイズ

具体的には、認証バックエンドを拡張して、カスタマイズすればいい。

認証バックエンドの実装

(GitHub)django.contrib.auth.backends.py

ベースのModelBackend.authenticateでは、以下のように取得している。

class ModelBackend(BaseBackend):
    :
    def authenticate(self, request, username=None, password=None, **kwargs):
        :
        user = UserModel._default_manager.get_by_natural_key(username)
        :

拡張クラスでは、DBのemailからusernameを検索するようにすればいいはず。とりあえずは、今回の運用は(1)の実装で問題ないので確認はしてないが、たぶん。

3.ログイン画面にお知らせ表示

ログイン画面の下に、DBから取得したお知らせ情報を表示するようにしたいので、修正する。

3-1)views.py:login関数の追加

1.ではLoginViewをurl.pyから直接呼び出すことで、views.pyの修正はなかったが、DBデータを取得するためにviews.pyに関数を追加する。

def login(request):
    """Renders the login page."""
    assert isinstance(request, HttpRequest)

    # news list
    news_list = Information.news.order_by('-from_time') # DBからお知らせ情報を取得

    view_obj = LoginView()
    view_obj.request = request
    view_obj.form_class = UserAuthenticationForm
    view_obj.template_name = 'app/login.html'
    view_obj.extra_context = {
        'title':'Login',
        'news_list':news_list,         # 追加のお知らせ情報リスト
    }

    return view_obj.dispatch(request)

3-2)url.pyの定義

LoginViewを直接呼び出していたのを、login関数に変更。

 :
from django.contrib.auth.views import LogoutView
from app import forms, views
 :
urlpatterns = [
   :
    path('login/', views.login, name='login'),     # 変更部分
    path('logout/', LogoutView.as_view(next_page='/'), name='logout'),
   :
]
 :

4.ログインが必要なページ

ログインが必要なページについては、以下でログインしていない場合、ログイン画面にリダイレクトさせる。

login_required デコレータ

クラスビューを使っている場合は、MixInを使う。

LoginRequired mixin

5.二段階認証の追加

これは、別記事で後日。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください