Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

認証

久々のDjangoネタ。
magic-removal版は更新が激しくなかなか落ち着きませんが・・・。
Djangoには組み込みで認証のフレームワークがついています。
http://ymasuda.jp/python/django/docs/authentication.html
にも書かれていますが。

from django.contrib.auth.decorators import login_required

def my_view(request):
    # ...
my_view = login_required(my_view)

とします。
ユーザがログインしていなければ, "/accounts/login/" にリダイレクトします。
このとき,現在のクエリの絶対 URL を next に入れ,例えば /accounts/login/?next=/polls/3/ のようにリダイレクトします。
ここまではドキュメントにも書かれています。

で実際ログイン処理はどうすればいいのさ?って話です。

上記でも書きましたが"/accounts/login/"にログインフォームを設定するわけですがせっかくなのでログインフォーム作成、認証もDjangoにやらせましょう。
url.py

from django.conf.urls.defaults import *
from django.conf import settings

urlpatterns = patterns('',
    # Example:
     (r'^/?accounts/login/$',  'django.contrib.auth.views.login'),
)

settings.py

・・・・・
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.markup',
・・・
)
・・・・

のように認証アプリ"django.contrib.auth"をインストールします。
"accounts/login/"にインストールしたcontribのviewを指定します。
そうすると"/accounts/login/"('django.contrib.auth.views.login')は"registration/login"ページを表示しようとします。
django.contrib.auth.views.loginの中身は以下

def login(request):
    "Displays the login form and handles the login action."
    manipulator = AuthenticationForm(request)
    redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '')
    if request.POST:
        errors = manipulator.get_validation_errors(request.POST)
        if not errors:
            # Light security check -- make sure redirect_to isn't garbage.
            if not redirect_to or '://' in redirect_to or ' ' in redirect_to:
                redirect_to = '/accounts/profile/'
            request.session[SESSION_KEY] = manipulator.get_user_id()
            request.session.delete_test_cookie()
            return HttpResponseRedirect(redirect_to)
    else:
        errors = {}
    request.session.set_test_cookie()
    return render_to_response('registration/login', {
        'form': forms.FormWrapper(manipulator, request.POST, errors),
        REDIRECT_FIELD_NAME: redirect_to,
        'site_name': Site.objects.get_current().name,
    }, context_instance=RequestContext(request))

Getの場合

    return render_to_response('registration/login', {
        'form': forms.FormWrapper(manipulator, request.POST, errors),
        REDIRECT_FIELD_NAME: redirect_to,
        'site_name': Site.objects.get_current().name,
    }, context_instance=RequestContext(request))

とformWrapper、元々アクセスしたいURL(redirect_to)も使えるようになります。

これを踏まえ自分のAPPのテンプレートのDirに"registration/login.html"を作成します。
registration/login.htmlの例

{% extends "base" %}
{% block content %}
{% if form.error_dict %}
    <p class="errornote">
    ログイン、パスワードが正しくありません。
    </p>
{% endif %}
<h3>ログイン</h3>
<form method="post" action="/accounts/login/?next={{ next }}">
<p>	<label for="id_username" />ユーザ名</label>{{form.username}}</p>
<p>	<label for="id_password" />パスワード</label>{{form.password}}</p>
	<input type="submit" />
</form>
{% endblock %}

nextにはログイン後リダイレクトするURLが入ります。
つまり最初にアクセスしようとした絶対 URL が next に入ります。
これで認証が通れば今後は認証なしでアクセスできます。
(デフォルトなので有効期間は2週間)

うくく。