破棄されたブログ

このブログは破棄されました。

Django のログイン要求ミドルウェア

この記事は、Django の全ページに一括でログイン要求(ユーザ認証)を設定させるためのミドルウェアに関する Ryan Witt 氏による記事、 Django Login Required Middleware を著者の許可のもと翻訳したものです。コード中のコメントも日本語訳されていますので、Python 2.x では注意してください。

わたしは Django Web フレームワークを使った プログラミングをたくさんして、ユーザがページを閲覧する前にログインをさせるこのコードスニペットについて考えてきました。

もし、あなたがすでに djangoperson なら、問題の背景について説明している冒頭の部分は読み飛ばしてください。

Django では、view と呼ばれる関数が HTTP リクエスに答えてユーザが閲覧するページを返します。 Django で view に機能を追加するには、Pythonデコレータを用いる方法が一般的です。 この方法を取ることで、多くのコードを書くことなく機能を追加することができます。 例えば、 Django は login_required と呼ばれるデコレータを提供していて、 このデコレータを view へ適用するとログインしていないユーザのページ閲覧を制限することができます。

@login_required      # これがデコレータ! 1 行でシンプル…
def my_view(request):
    # リクエストに応じて HTML ページを返すための処理
    # ...

あなたの複雑なサイトのページ全てに login_required デコレータを使わなければならないような場合、この方法は本当に苦痛です。 もし、繊細な情報が含まれているページで view のデコレータを忘れてしまったらどうなるでしょう? 幸いにも、Django では、全てのリクエストをフックしてサイト全体に機能を追加できるミドルウェアを書くことができます。 わたしのミドルウェアは、シンプルに各リクエストを捕まえてログイン前のユーザをログインページへリダイレクトさせます。 また、ログイン前にも閲覧できるページを正規表現で指定することもできます。

from django.http import HttpResponseRedirect
from django.conf import settings
from re import compile

EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))]
if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
    EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]

class LoginRequiredMiddleware:
    """
    LOGIN_URL 以外のページでユーザ認証を要求するミドルウェア。
    ユーザ認証を免除するページは、 LOGIN_EXEMPT_URLS に正規表現で指定する
    必要がある。(これを urls.py にコピーすることもできる)
    ログイン要求ミドルウェアとコンテキストプロセッサーのテンプレートが
    読み込まれる。読み込まれなかった場合、エラーが発生するかもれない。
    """
    def process_request(self, request):
        assert hasattr(request, 'user'), "ログイン要求ミドルウェア\
はユーザ認証ミドルウェアのインストールを要求します。MIDDLEWARE_CLASSES を\
編集して、'django.contrib.auth.middlware.AuthenticationMiddleware' を\
追加してください。動作しない場合、 TEMPLATE_CONTEXT_PROCESSORS 設定が\
'django.core.context_processors.auth' に読み込まれていることを\
確認して下さい。"
        if not request.user.is_authenticated():
            path = request.path_info.lstrip('/')
            if not any(m.match(path) for m in EXEMPT_URLS):
                return HttpResponseRedirect(settings.LOGIN_URL)

# settings.py

LOGIN_URL = '/login/'

LOGIN_EXEMPT_URLS = (
 r'^about\.html$',
 r'^legal/', # allow any URL under /legal/*
) 

MIDDLEWARE_CLASSES = (
    # ...
    'python.path.to.LoginRequiredMiddleware',
)

このミドルウェア書いているとき、 davyd による類似の解決策と django-users リストのディスカッションを見つけましたが、 いずれも正規表現による柔軟性を持っていませんでした。

このミドルウェアが役に立ったり何か問題があったりした場合は、ぜひ教えて下さい!

広告を非表示にする