認証処理
djangoで認証処理を実装してみました。(DjangoでTodoアプリケーションの作成の続きとして)
認証のための設定
settings.pyのアプリケーションリストにdjango.contribut.authが含まれている必要があります。(デフォルトで含まれている)
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'djsite.todo', )
settings.pyのミドルウェアリストにAuthenticationMiddlewareが含まれている必要があります。(デフォルトで含まれている)
MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', )
データベースのインストール
上記の設定がされている状態で、管理スクリプトでsyncdb(データベース同期)を行うと認証関連のデータベーステーブルの生成、初期化が行われます。
./manager.py syncdb
認証フォーム
認証ページの表示に対応するフォームを定義しました。
from django import forms from django.contrib.auth.models import User from django.contrib.auth import authenticate, login ..... .... class LoginForm(forms.Form): username = forms.CharField(label="ユーザー名", required=True, max_length=30) password = forms.CharField(label="パスワード", required=True, max_length=30, widget=forms.PasswordInput) def clean_auth(self): if not self.is_valid(): return self.cleaned_data user = authenticate(username=self.cleaned_data['username'], password=self.cleaned_data['password']) if user is not None: if user.is_active: self.cleaned_data['user'] = user return self.cleaned_data else: raise forms.ValidationError('Authorication error.') else: raise forms.ValidationError('Authorication error.') def clean(self): cleaned = forms.Form.clean(self) self.clean_auth() return cleaned
-
- フォームのclean()メソッドをオーバーライドして認証に失敗したときにValidationErrorが投げられるようにしています。フォームのvalidationが走ったときこの例外が投げられるとにエラーリスト(errors)にエラーが追加されるようになります。
- 認証自体は、django.contrib.authのauthenticate関数で行っています。これでインストールされているユーザテーブル(auth_user)を検索して認証が行われます。
認証ページの表示と認証の実行
ビュー(views.py)に認証ページの表示と認証を行う関数を追加します。
from django.http import HttpResponse,HttpResponseRedirect from django.shortcuts import render_to_response from djsite.todo.forms import LoginForm def show_login(request): if request.POST: form = LoginForm(request.POST) next = request.POST.get('next', None) next = request.GET.get('next', None) if not form.is_valid(): return render_to_response('registration/login.html', dict(form=form, next=next)) cleaned = form.clean() login(request, cleaned['user']) return HttpResponseRedirect(next) else: next = request.POST.get('next', None) form = LoginForm() return render_to_response('registration/login.html', dict(form=form, next=next))
-
- POSTであれば、認証を実行、GETであれば認証ページの表示を行います。
- 認証成功後に遷移するページのパスがリクエストパラメータでnext受け渡していきます。
- 認証が成功すれば、django.contrib.authのlogin関数で認証情報をセッションに登録、次のページに遷移します。
認証ページへのリダイレクト
認証が必要なViewの場合、認証ページへリダイレクトされるようにします。
from django.http import HttpResponse,HttpResponseRedirect from django.contrib.auth import authenticate, login from django.contrib.auth.decorators import login_required from django.shortcuts import render_to_response from djsite.todo.forms import LoginForm .... @login_required def show_list(request): """docstring for show_list""" user = request.user ..... ...
-
- デコレーターとして、django.contrib.auth.decoratorsのlogin_requiredを指定します。これにより、認証を確認して、認証されていなければ認証ページ(URLパターン「accounts/login/」で指定されるView)へリダイレクトされます。
- requeseのuser属性として、認証情報が参照できます。
URLパターンの追加
from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: # from django.contrib import admin # admin.autodiscover() urlpatterns = patterns('djsite.todo.views', (r'^list$','show_list'), (r'^accounts/login/','show_login'), (r'^accounts/logout/','logout'), )
-
- 「^accounts/login/」というパターンが認証ViewへのUrlとなるので、そのパターンに対する関数を指定します。
テンプレート
ユーザ認証ページのテンプレートです。作成した認証フォーム(LoginForm)の属性と次に遷移するurl値をフォーム要素として含みます。
<head> </head> <body> <h1>Login</h1> {%if form.errors %} <p style="color: red;"> 認証に失敗しました。 </p> {% endif %} <form action="/accounts/login/?next={{ request.GET.next }}" method="post"> <table> <tr> <td> <label class="fortextinput" for="id\_username"> Username: </label> </td> <td> {{ form.username }} {%if form.username.errors %} <span style="color: red;"> {{ form.username.errors|join:", " }} </span> {% endif %} </td> </tr> <tr> <td> <label class="fortextinput" for="id\_password"> Password: </label> <td> {{ form.password }} {%if form.password.errors %} <span style="color: red;"> {{ form.password.errors|join:", " }} </span> {% endif %} </td> </tr> </table> <input type="hidden" name="next" value="{{next}}"/> <input type="submit" value="Login"/> </form> </body>