このドキュメントの Django のバージョンにはセキュリティ上の脆弱性があるため、すでにサポートが終了されています。新しいバージョンにアップグレードしてください!最新の Django のバージョンのドキュメントはこちら

Django v1.0 documentation

Django でのユーザ認証

revision-up-to:8961 (1.0)

Django にはユーザ認証システムがついてきます。 Django のユーザ認証システムは、 ユーザアカウント、グループ、パーミッションとクッキーベースのユーザセッショ ンを扱えます。このドキュメントでは、ユーザ認証の仕組みについて説明します。

概要

認証システムは以下の要素から成り立っています:

  • ユーザ (Users)
  • パーミッション: あるユーザが特定のタスクを実行してよいかどうかを決め る、バイナリ (yes/no) のフラグです。
  • グループ (Groups): 複数のユーザに対してラベル付したり、認証を設定した りするための一般的な方法です。
  • メッセージ (Messages): 指定のユーザ(達) に対するメッセージをキューす るための簡単な方法です。

インストール

認証のサポートは Django アプリケーションとして django.contrib.auth にバ ンドルされています。インストールするには、以下のようにします:

  1. INSTALLED_APPS 設定に 'django.contrib.auth' を加えま す。
  2. manage.py syncdb を実行します。

django-admin.py startproject が生成するデフォルトの settings.py ファイルの INSTALLED_APPS には、簡便のため 'django.contrib.auth' が最初から入っています。この場合は、単に manage.py syncdb するだけでかまいません。 manage.py syncdb はその都度必要なものだけをインストールするので、 何度実行してもかまいません。

syncdb コマンドは必要なデータベーステーブルを作成し、インストー ル済みのアプリケーションで必要な全てのパーミッションオブジェクトを作成しま す。また、最初に実行したときには、ユーザにスーパユーザアカウントを作成する よう促します。

これだけで、認証サポートを使えるようになります。

ユーザ (User)

class models.User

API リファレンス

フィールド

class models.User

User objects have the following fields:

username
必須です。30 文字以下の文字列で、英数字 (アルファベット、数字、アン ダースコア) だけを使えます。
first_name
オプションです。30 文字以下です。オプションです。30 文字以下です。
last_name
オプションです。 30 文字以下です。
email
オプションです。 E-mail アドレスです。
password
必須です。パスワードのメタデータであるハッシュ値です (Django では生 のパスワードを保存しません)。生のパスワードは任意の長さでよく、どん な文字が入っていても構いません。詳しくは以下の「パスワード」の節を 参照して下さい。
is_staff
Bool 値です。この値が真なら、ユーザは admin サイトにアクセスできま す。
is_active
Bool 値です。この値が真なら、このアカウントを使ってログインできます。 アカウントを削除する代わりに、この値を False に設定してください。
is_superuser
Bool 値です。この値が真なら、ユーザは明示的な指定がなくても全てのパー ミッションを得ます。
last_login
ユーザが最後にログインした時刻を表す datetime オブジェクトです。デ フォルトではログイン時現在の日付/時刻になります。
date_joined
アカウントの作成された時刻を表す datetime オブジェクトです。デフォ ルトではアカウント作成時現在の日付/時刻になります。

メソッド

class models.User

User オブジェクトには groupsuser_permissions という二つの多対多のフィールドがあります。この 関係性のために、 User オブジェクト は他の Django モデル と同じようにして、関連づ けされたオブジェクトにアクセスできます:

myuser.groups = [group_list]
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

自動的に生成されるこれらの API に加え、 User オブジェクトには以下のカス タムメソッドがあります:

is_anonymous()
常に False を返します。 User オブジェクトを AnonymousUser オブジェクトと 区別する手段の一つです。 通常は、 is_authenticated()`() メソッ ドを使うようにしてください。
is_authenticated()
常に True を返します。ユーザを認証済みかどうかを調べる一つの方 法です。このメソッドの戻り値は、ユーザが正しいパーミッションを持っ ているか、あるいはアクティブなユーザであるかどうかに関係なく、ユー ザが正しいユーザ名とパスワードを入力したことだけを示します。
get_full_name()
first_namelast_name をスペースでつな げた文字列を返します。
set_password(raw_password)
渡された文字列をハッシュ化し、ユーザのパスワードに設定します。 User オブジェクトの保存は行い ません。
check_password(raw_password)
渡された文字列がこのユーザの正しい文字列ならば True を返します。 (このメソッドは比較時にパスワードのハッシュ処理を行います)
set_unusable_password()
Django 1.0 で新たに登場しました.

ユーザにパスワード未設定のマークをつけます。パスワード未設定の状態 は、パスワードが空の文字列である状態と区別されます。パスワード未設 定状態のユーザに対して check_password() を呼び出 すと、決して True を返しません。このメソッドは User オブジェクトを直接保存し ません。

この機能は、 LDAP ディレクトリのような外部の認証ソースを使ってアプ リケーションの認証を行いたい場合に必要です。

has_usable_password()
Django 1.0 で新たに登場しました.

ユーザに対して set_unusable_password() を 呼び出し、パスワードが未設定状態であれば False を返します。

get_group_permissions()
ユーザが自分の属するグループから得ているパーミッションを表す文字列 からなるリストを返します。
get_all_permissions()
ユーザ自身のもつパーミッションと、ユーザの属するグループのパーミッ ションの両方からなるリストを返します。
has_perm(perm)
ユーザが特定のパーミッションを持っている場合に True を返します。 パーミッション名 perm は "package.codename" のような形式で表し ます。ユーザがアクティブでない場合、このメソッドは常に False を 返します。
has_perms(perm_list)
ユーザが perm_list 内のパーミッションのいずれかを持っている場合に True を返します。各々のパーミッション名は "package.codename" のような形式で表します。 ユーザがアクティブ でない場合、このメソッドは常に False を返します。
has_module_perms(package_name)
ユーザが指定した名前のパッケージ (アプリケーション) の何らかのパー ミッションを持っていれば True を返します。ユーザがアクティブで ない場合、このメソッドは常に False を返します。
get_and_delete_messages()
ユーザのキューに入っている Message オブジェクトを返し、入っ ていたメッセージをキューから取り除きます。
email_user(subject, message, from_email=None)
ユーザにメールを送信します。 from_emailNone の場合、 Django は DEFAULT_FROM_EMAIL 設定を使います。
get_profile()
ユーザのサイト固有のプロファイル (site-specific profile) を返します。 プロファイルを使えないサイトでは django.contrib.auth.models.SiteProfileNotAvailable を送出し ます。サイト固有のユーザプロファイルを定義するには、後述の 追加のユーザ情報の保存 を参照して下さい。

マネジャ関数

class models.UserManager

User モデルには、以下のヘルパ関数 を備えたマネジャがあります。

create_user(username, email, password=None)

ユーザを生成して保存し、生成された User を返します。 username, email および password は指定した値にな り、 is_activeTrue に設定されます。

パスワードを指定しなかった場合、 set_unusable_password() を 呼び出します。

使い方は ユーザの作成 を参照してください。

make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')
指定した長さのランダムなパスワードを生成して返します。パスワードに 使える文字は文字列で指定します。(allowed_chars のデフォルト値は、 ユーザの見間違いを防ぐため i, I, l, o, 1, 0 を除いてあります。)

基本的な使い方

ユーザの作成

ユーザを作成する一番基本的な方法は、オブジェクトマネージャの create_user() ヘルパー関数を 使う方法です:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
>>>
# この操作で、User オブジェクト user を保存できるようになります。
# 他のフィールドを変更したければ、属性を変更します。
>>> user.is_staff = True
>>> user.save()

パスワードの変更

パスワードの変更には set_password() を使います:

>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username__exact='john')
>>> u.set_password('new password')
>>> u.save()

特別な意図のない限り、 password 属性を直接設定しないでください。これについては次節で説明します。

パスワード

User オブジェクトの password フィールドは、以下の形式:

hashtype$salt$hash

すなわちハッシュ方式 (hashtype)、ハッシュソルト (salt)、そしてハッシュ値 (hash) をドル記号 ("$") で分割した文字列形式をとります。

ハッシュ形式は sha1 (デフォルト) または md5crypt のいずれか で、それぞれパスワードの一方向ハッシュ化アルゴリズムを表します。 salt は生 のパスワード文字列からハッシュを生成するときに味付け (salt) しておくための ランダムな文字列です。 crypt のサポートは、 Python の標準モジュール crypt がサポートされている環境だけで有効です。また、 crypt のサポー トは開発版の Django でのみ利用できます。

例えば:

sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4

User.set_password() および User.check_password() set_password() および関数は、これら の値の設定やチェックを背後で行っています。

バージョン 0.90 のような以前の Django では、パスワードソルトなしの単純な MD5 ハッシュを使っていました。この形式は、以前のバージョンとの互換性を持た せるためにまだサポートしています。ただし、古いパスワードのユーザに対する check_password() が成功すると、パ スワードは自動的に新しい形式に変換されます。

匿名ユーザ (Anonymous users)

class models.AnonymousUser

django.contrib.auth.models.AnonymousUserdjango.contrib.auth.models.User と同じインタフェースを実装した クラスですが、以下の点で User と異 なります:

おそらく、実践上意識して AnonymousUser オブジェクトを使う必要はないはずです。とはいえ、匿名ユーザは次節で述べるよ うな形で Web リクエストで使われています。

スーパユーザの作成

Django 1.0 で新たに登場しました: manage.py createsuperuser コマンドが追加されました。

INSTALLED_APPS'django.contrib.auth' を追加した直後に manage.py syncdb を実行すると、スーパユーザの作成を促す プロンプトを表示します。後でスーパユーザを作成したい場合には、以下のように コマンドラインユーティリティを使います。

manage.py createsuperuser --username=joe --email=joe@example.com

ユーティリティはパスワードの入力を促します。入力すると、ユーザは即座に作成 されます。 --username--email オプションを省 略すると、ユーティリティはそれらの値を入力するよう促します。

古い Django も使っている場合、以前からあるコマンドラインのスーパユーザ作成 方法も使えます:

python /path/to/django/contrib/auth/create_superuser.py

/path/to/ は自分のシステムの Django コードベースへのパスに応じて読 み変えて下さい。 manage.py は自動的に正しいパスと環境変数を決定するので、 manage.py を使うよう推奨します。

追加のユーザ情報の保存

ユーザに追加の情報をひもづけて保存したい場合のために、 Django ではサイトご とにユーザに関連付けられた「ユーザプロファイル」を取り出すためのメソッドを 提供しています。

ユーザプロファイルを利用するには、まず、ユーザにひもづけて保存したい情報を 入れるためのフィールドや持たせたいメソッド、そして User モデルへの ForeignKey を持ったモデルを定義します。 ForeignKey には unique=True をセットし、 ユーザごとにモデルが一つだけ生成されるようにします。

このモデルをあるサイトのユーザプロファイルモデルにするには、 AUTH_PROFILE_MODULE に以下の内容をドット区切りの文字列で指定しま す:

  1. ユーザプロファイルモデルを定義している (小文字に変換した) アプリケーショ ン名 (別の言い方をするなら、 manage.py startapp で アプリケーションを作成するときに指定する名前を全て小文字にしたもの)。
  2. (小文字に変換した) モデルクラス名

例えば、プロファイルモデルが UserProfile という名前のクラスで、 accounts というアプリケーションで定義されているなら、設定値は以下のよう になるでしょう:

AUTH_PROFILE_MODULE = 'accounts.userprofile'

上記の方法でユーザプロファイルモデルを定義して指定すると、ユーザオブジェ クトには get_profile() というメソッ ドが付加されます。このメソッドは、ユーザに関連付けられているプロファイルモ デルのインスタンスを返します。

さらに詳しい情報は、 Django book の 12 章 を参照してください。

Web リクエストに対する認証

ここまでのドキュメントは、認証関連のオブジェクトを操作するための低水準の API について扱ってきました。より高水準の API では、 Django はこれらの認証フ レームワークを リクエストオブジェクト シ ステム内にフックできます。

まず、 SessionMiddleware およ び AuthenticationMiddlewareMIDDLEWARE_CLASSES 設定に追加して、これらのミドルウェアをインス トールします。詳しくは セッションのドキュメント を参照してください。

ミドルウェアをインストールしたら、ビューから request.user にアクセスできるように なります。 request.user は現在ログイ ンしているユーザの User オブジェクトを 表します。ユーザがログインしていなければ、 request.userAnonymousUser のインスタンスになります (前節を参照してください)。ログインユーザと匿名ユーザは、 is_authenticated() で以下のように 区別できます:

if request.user.is_authenticated():
    # Do something for authenticated users.
else:
    # Do something for anonymous users.

ユーザをログインさせる

Django では、 django.contrib.auth の中で、 authenticate()login() という二つの関数を提供しています。

authenticate()

あるユーザ名とパスワードに対する認証を行うには、 authenticate() を使ってください。この関数 は二つのキーワード引数、 usernamepassword をとり、ユーザ名 に対してパスワードが有効であった場合に User オブジェクトを返します。パス ワードが無効だった場合には、 authenticate()None を返します。例 えば:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
    if user.is_active:
        print "You provided a correct username and password!"
    else:
        print "Your account has been disabled!"
else:
    print "Your username and password were incorrect."
login()

ユーザをログインさせるには、ビューの中で login() を使ってください。この関数は HttpRequest オブジェクトと User オブジェクトを引数にとります。 login() は Django のセッションフレームワー クを使って、ユーザの ID をセッションに保存します。従って、上でも述べた ように、セッションミドルウェアをインストールしておかねばなりません。

以下の例は authenticate()login() の使い方を示しています:

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
    else:
        # Return an 'invalid login' error message.

authenticate() は最初に呼び出してください

ユーザを手動でログインさせる場合、 login() を呼び出す前に 必ず authenticate() を呼び出してください。 authenticate() は、 User オブジェクトに、そのユーザが 認証バックエンドによって正しく認証されたことを示す属性を付加します。 (詳しくは 認証バックエンドのドキュメント を参照してください) この情報が後でログインの処理で必要だからです。

ユーザのパスワードを手動で調べる

check_password()
ユーザ認証を手動で行うために平文パスワードとデータベース上のハッシュ化 パスワードを比較したい場合には、 django.contrib.auth.models.check_password() という便宜関数を使えます。この関数は、調べたい平文パスワードと、比較対 象のデータベースに格納されているユーザの password フィールド全体の 二つの引数をとり、二つが一致すれば True を、そうでなければ False を返します。

ユーザをログアウトさせる

logout()

django.contrib.auth.login() でログインしたユーザをログアウトさ せるには、ビューの中で django.contrib.auth.logout() を使ってください。この関数は、 HttpRequest オブジェクトを引数に取り、戻り値を持 ちません。例を以下に示します:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    # Redirect to a success page.

ユーザがログインしていなくても logout() は エラーを送出しないことに注意してください。

Django 1.0 で変更されました: logout() を呼び出すとセッションデータを消去するようになりました。

logout() を呼び出すと、現在のリクエストに 結び付いたセッションデータを全て抹消します。その時に記憶されていたデー タは全て除去されます。これは、他のユーザが同じブラウザを使ってログイン し、直前にブラウザを使っていたユーザのセッションデータを読み出したりで きないようにするためです。ユーザのログアウト後に何らかのセッションデー タを記憶させたければ、 django.contrib.auth.logout()後で 行ってください。

ログインユーザだけがアクセスできるように制限をかける

生真面目な方法

ページへのアクセスを制限する単純で生真面目な方法は、 request.user.is_authenticated() をチェックして、ログインページにリダイレクトするというものです:

from django.http import HttpResponseRedirect

def my_view(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/?next=%s' % request.path)
    # ...

...あるいは、エラーメッセージを出しても構いません:

def my_view(request):
    if not request.user.is_authenticated():
        return render_to_response('myapp/login_error.html')
    # ...

login_required デコレータ

decorators.login_required()

手間を省くために、 login_required() デコレータを使え ます:

from django.contrib.auth.decorators import login_required

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

Python 2.4 で登場したよりコンパクトなデコレータ構文を使った例を以下に示 します:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    # ...
Django ``redirect_field_name`` で変更されました: パラメタが追加されました。

login_required() はオプションの redirect_field_name パラメタをとります。例えば:

from django.contrib.auth.decorators import login_required

def my_view(request):
    # ...
my_view = login_required(redirect_field_name='redirect_to')(my_view)

同様に、 Python 2.4 で登場したよりコンパクトなデコレータ構文を使った例 を以下に示します:

from django.contrib.auth.decorators import login_required

@login_required(redirect_field_name='redirect_to')
def my_view(request):
    # ...

login_required() が行うのは以下の ような処理です:

  • ユーザがログインしていなければ、 settings.LOGIN_URL に指定した値 (デフォル トでは /accounts/login/) にリダイレクトします。このとき、現在 のクエリの絶対 URL を next または redirect_field_name に 指定したパラメタの値に設定します。 URL は例えば /accounts/login/?next=/polls/3/ のようになります。
  • ユーザがログインしていれば、 ビューを普通に実行します。ビューコー ドの中では、ユーザがログインしているものとみなして構いません。

ただし、これを行うには settings.LOGIN_URL に適切な Django のビュー関数を対応づけておかねばなりません。例えば URLconf に以下の ような行を設定します:

(r'^accounts/login/$', 'django.contrib.auth.views.login'),
views.login()

django.contrib.auth.views.login は以下のような処理を行います:

  • GET で呼び出されると、同じ URL に対して POST を行うためのログ インフォームを表示します。これについては後でもう少し説明します。
  • POST で呼び出されると、ユーザのログイン処理を試みます。ログイ ンに成功すると、ビューは next に示された URL にリダイレクトし ます。 next を指定しない場合、 settings.LOGIN_REDIRECT_URL (デフォルト値は /accounts/profile/) にリダイレクトします。ロ グインに失敗すると、ログインフォームを再度表示します。

開発者は registration/login.html という名前のテンプレート上でログイ ンフォームを提供せねばなりません。 Django はこのテンプレートに、以下の 3 つのテンプレートコンテキスト変数を渡します:

  • form: ログインフォームを表現する Form オブジェクトです。 Form オブジェクトの詳細 は forms のドキュメント を参照してく ださい。

  • next: ログイン成功後にリダイレクトされる先の URL です。 URL にはクエリ文字列を含めてかまいません。

  • site_name: SITE_ID によって決定される現在の Site` の名前です。

    Django 1.0 で変更されました: sites フレームワークを組み込んでいないときの値は request.META['SERVER_NAME'] の値に設定されます。 site フレームワークの詳細は "sites" フレームワーク を参照し てください。

registration/login.html テンプレートを呼び出したくないのなら、 URLconf を通じて外部パラメタ template_name をビューに渡してください。 例えば、 myapp/login.html を使いたければ、URLconf の行は以下の ようになります:

(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}),

編集の雛型にできるような registration/login.html テンプレートの 例を以下に示します。このテンプレートは、 content ブロックの定義された base.html があるという前提で書かれています:

{% extends "base.html" %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

<form method="post" action=".">
<table>
<tr><td>{{ form.username.label_tag }}</td><td>{{ form.username }}</td></tr>
<tr><td>{{ form.password.label_tag }}</td><td>{{ form.password }}</td></tr>
</table>

<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>

{% endblock %}

その他の組み込みビュー

認証システムでは、 login ビューの他にも便利なビューをいくつか提供してい ます:

django.contrib.auth.views.logout()

ユーザをログアウトさせます。

オプション引数:

  • template_name: ログアウトページのテンプレートの完全な名前です。 この引数を省略すると、デフォルト値の registration/logged_out.html を使います。

テンプレートコンテキスト:

  • title: "Logged out" という文字列を翻訳した値になります。
django.contrib.auth.views.logout_then_login()

ユーザをログアウトさせてから、ログインページにリダイレクトします。

オプション引数:

  • login_url: ログインページへのリダイレクト先です。この引数を省 略すると、デフォルト値の settings.LOGIN_URL を使います。
django.contrib.auth.views.password_change()

ユーザがパスワードを変更できるようにします。

オプション引数:

  • template_name: パスワード変更ページのテンプレートの完全な名前 です。この引数を省略すると、デフォルト値の registration/password_change_form.html を使います。

テンプレートコンテキスト:

  • form: パスワード変更のためのフォームです。
django.contrib.auth.views.password_change_done()

ユーザがパスワードを変更した後のページを表示するためのビューです。

オプション引数:

  • template_name: パスワード変更完了ページのテンプレートの完全な 名前です。この引数を省略すると、デフォルト値の registration/password_change_done.html を使います。
django.contrib.auth.views.password_reset()

ユーザがパスワードをリセットできるようにします。また、新たなパスワード をメールで送信します。

オプション引数:

  • template_name: パスワードリセットページのテンプレートの完全な 名前です。この引数を省略すると、デフォルト値の registration/password_reset_form.html を使います。
  • email_template_name: 新しいパスワードを e-mail で送信する際に 使うテンプレートの完全な名前です。この引数を省略すると、デフォル ト値の registration/password_reset_email.html を使います。

テンプレートコンテキスト:

  • form: パスワードリセットのためのフォームです。
django.contrib.auth.views.password_reset_done()

ユーザがパスワードをリセットした後のページを表示するためのビューです。

オプション引数:

  • template_name: パスワードリセット完了ページのテンプレートの完 全な名前です。この引数を省略すると、デフォルト値の registration/password_reset_done.html を使います。
django.contrib.auth.views.redirect_to_login()

ログインページにリダイレクトし、ログインに成功したら別の URL に戻れるよ うにするためのビューです。

必須の引数:

  • next: ログイン成功後のリダイレクト先 URL です。

オプション引数:

  • login_url: ログインページへのリダイレクト先です。 この引数を省略すると、デフォルト値の settings.LOGIN_URL を使います。

組み込みフォーム

Django 1.0 で新たに登場しました.

組み込みビューを使いたくないけれども、フォームクラスを書かずに済ませたい場 合のために、認証システムでは組み込みのフォームをいくつか提供しています:

  • django.contrib.auth.forms.AdminPasswordChangeForm: Admin イ ンタフェースでユーザのパスワード変更に使われているフォームです。
  • django.contrib.auth.forms.AuthenticationForm: ユーザをログイ ンさせるためのフォームです。
  • django.contrib.auth.forms.PasswordChangeForm: ユーザにパスワー ドを変更させるためのフォームです。
  • django.contrib.auth.forms.PasswordResetForm: パスワードをリ セットし、新たなパスワードを送信するためのフォームです。
  • django.contrib.auth.forms.UserCreationForm: 新たなユーザを作 成するためのフォームです。

テストにパスしたログインユーザだけがアクセスできるように制限をかける

特定のパーミッションやその他のテストの結果に応じたアクセスの制限には、前節 で説明したの本質的に同じことをします。

一番簡単な方法は、ビュー内で直接 request.user に対するテストを実行す るというものです。例えば、以下のビューではユーザがログイン済みで、かつ polls.can_vote というパーミッションを持っているかチェックします:

def my_view(request):
    if not (request.user.is_authenticated() and request.user.has_perm('polls.can_vote')):
        return HttpResponse("You can't vote in this poll.")
    # ...
decorators.user_passes_test()

user_passes_test デコレータを使えば、手間を省けます:

from django.contrib.auth.decorators import user_passes_test

def my_view(request):
    # ...
my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'))(my_view)

ここでは、簡単な例としてパーミッションのテストに user_passes_test() を使っています が、単にあるユーザがあるパーミッションを有しているかをテストしたいだけ なら、後で解説する django.contrib.auth.decorators.permission_required() デコレータ を使えます。

Python 2.4 のデコレータ構文ならこうなります:

from django.contrib.auth.decorators import user_passes_test

@user_passes_test(lambda u: u.has_perm('polls.can_vote'))
def my_view(request):
    # ...

user_passes_test() には必須の引数 が一つあります。この引数は、 User を引数に取り、ユーザにページのビューを許可する場合には True を返す 呼び出し可能オブジェクトでなければなりません。 user_passes_test()User が匿名かどうかを自動的に調べ ないので注意してください。

user_passes_test() はオプション の引数として login_url をとります。この引数を使うとログインページへ の URL を指定できます (デフォルトでは settings.LOGIN_URL になります)。

Python 2.3 風の構文で書いた例を示します:

from django.contrib.auth.decorators import user_passes_test

def my_view(request):
    # ...
my_view = user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/')(my_view)

Python 2.4 風の構文で例を書くと以下のようになります:

from django.contrib.auth.decorators import user_passes_test

@user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/')
def my_view(request):
    # ...

permission_required デコレータ

Django 1.0 で新たに登場しました.
decorators.permission_required()

あるユーザが特定のパーミッションを有しているかのチェックは、比較的よく ある操作なので、 Django はショートカットとして permission_required() という デコレータを用意しています。このデコレータを使うと、上の例は以下のよう に書き直せます:

from django.contrib.auth.decorators import permission_required

def my_view(request):
    # ...
my_view = permission_required('polls.can_vote')(my_view)

permission_required() もまた、 login_url を引数に取れます。例えば:

from django.contrib.auth.decorators import permission_required

def my_view(request):
    # ...
my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view)

login_required デコレータと同様、 login_url のデフォルト値は settings.LOGIN_URL です。

アクセスを汎用ビューに制限する

アクセスを 汎用ビュー に制限するには、ビューを 囲む薄いラッパコードを書き、URLconf を変更して、ジェネリックビュー自体では なくラッパコードを指すようにします。例えば:

from django.views.generic.date_based import object_detail

@login_required
def limited_object_detail(*args, **kwargs):
    return object_detail(*args, **kwargs)

パーミッション (Permission)

Django には単純なパーミッション機構がついてきます。このパーミッション機構は 特定のユーザやユーザのグループに対してパーミッションを結びつける手段を提供 します。

パーミッション機構は Django の admin サイトでも使われていますが、自作のコー ド内でも自由に使えます。

  • "add" フォームをビューし、オブジェクトを追加するためのアクセスを、そ の型のオブジェクトの "add" パーミッションを持つユーザに制限しています。
  • 変更リストをビューし、"change" フォームをビューしてオブジェクトを変更 するためのアクセスを、その型のオブジェクトの "change" パーミッション を持つユーザに制限しています。
  • あるオブジェクトを削除するためのアクセスを、その型のオブジェクトの "delete" パーミッションを持つユーザに制限しています。

パーミッションはオブジェクトインスタンスごとではなく、オブジェクトの型ごと にグローバルに設定されます。例えば、「Mary はニュース記事を変更できる」のよ うには書けますが、現状では、「Mary はニュース記事を変更できる。ただし彼女が 書いた分だけ」とか、「Mary はある状態にある記事か、ある日時に出版されたか、 ある ID の記事だけを変更できる」のようには書けません。後者の機能については は、現在 Django の開発者達が議論中です。

デフォルトのパーミッション

INSTALLED_APPS 設定に django.contrib.auth を追加している場合、 インストールされている全てのアプリケーションのモデルについて、追加 (add)、 変更 (change)、および削除 (delete) というデフォルトのパーミッションが作成さ れます。

これらのパーミッションは、 manage.py syncdb を実行した ときに生成されます。厳密には、 django.contrib.authINSTALLED_APPS 設定に追加した直後に syncdb を実行する と、その時インストールされていた全てのアプリケーションと、新たに追加したア プリケーションのデフォルトパーミッションが作成されます。以後、 manage.py syncdb を実行するたびに、新たに追加されたモデ ルのデフォルトパーミッションが生成されます。

カスタムのパーミッション

カスタムのパーミッションを生成するには、 permissions という モデルのメタ属性 を使います。

この例では、三つのカスタムパーミッションを生成しています:

class USCitizen(models.Model):
    # ...
    class Meta:
        permissions = (
            ("can_drive", "Can drive"),
            ("can_vote", "Can vote in elections"),
            ("can_drink", "Can drink alcohol"),
        )

この定義の役割は、 manage.py syncdb を実行したときに追 加のパーミッションを追加することだけです。

API リファレンス

class models.Permission
ユーザと同様、パーミッションは Django モデルとして実装されています。実 装は django/contrib/auth/models.py にあります。

フィールド

Permission オブジェクトには以下のフィー ルドがあります:

models.Permission.name
必須です。50 文字以下です。例: 'Can vote'
models.Permission.content_type
必須です。インストール済みの Django モデルのレコードが入った django_content_type データベーステーブルへの参照です。
models.Permission.codename
必須です。 100 文字以下です。例: 'can_vote'

メソッド

Permission オブジェクトは、他の Django モデル <ref-models-instances> と同じく、標準的なデータアクセスメソッ ドを備えています。

認証データのテンプレート上での扱い

RequestContext を使っている場合、ログイン ユーザとそのパーミッションに テンプレートコンテキスト (template context) を使っ てアクセスできます。

技術的な話題

デフォルトの設定では、テンプレートコンテキストに RequestContext を使うようになっていて、 かつ TEMPLATE_CONTEXT_PROCESSORS の設定に "django.core.context_processors.auth" が入っています。この場合にのみ、 上記の変数をテンプレートコンテキストの中で使えるようになります。詳しくは RequestContext のドキュメント を参照してください。

ユーザ

現在のログインユーザは、 User インスタ ンスであっても AnonymousUser インスタ ンスであっても、テンプレート変数 {{ user }} に入ります:

{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
    <p>Welcome, new user. Please log in.</p>
{% endif %}

パーミッション

現在のログインユーザのパーミッションはテンプレート変数 {{ perms }} に入っ ています。この変数はパーミッションオブジェクトをテンプレートで扱いやすくす るためのプロキシ (proxy) である、 django.core.context_processors.PermWrapper のインスタンスです。

{{ perms }} オブジェクトに対して 1 段の属性参照を行うと、実際には User.has_module_perms へのプロキシになっています。例えば下記の例は、ログインユーザが foo とい うアプリケーションへのパーミッションを持っている場合に True を表示しま す:

{{ perms.foo }}

2 段階属性を参照すると、 User.has_perm へのプロキ シに到達します。以下の例では、ログインユーザが foo.can_vote へのパーミッ ションを持つ場合に True を表示します:

{{ perms.foo.can_vote }}

こうして、テンプレート内で {% if %} 文を使ってチェックを行えます:

{% if perms.foo %}
    <p>You have permission to do something in the foo app.</p>
    {% if perms.foo.can_vote %}
        <p>You can vote!</p>
    {% endif %}
    {% if perms.foo.can_drive %}
        <p>You can drive!</p>
    {% endif %}
{% else %}
    <p>You don't have permission to do anything in the foo app.</p>
{% endif %}

グループ (Group)

グループは、パーミッションを適用するユーザのカテゴリを作ったり、一連のユー ザに何らかのラベルを適用するための汎用的な手段です。一人のユーザは複数のグ ループに所属できます。

グループに所属したユーザは、そのグループに許可されているパーミッションを自 動的に得ます。例えば、 Site editors というグループに can_edit_home_page というパーミッションをがあれば、そのグループに属する ユーザはみな, can_edit_home_page のパーミッションを持ちます。

パーミッションだけではなく、グループはユーザをカテゴリに分けてラベルを付け たり、機能を拡張したりできます。例えば、 '特別なユーザ' のグループを作 成して、そのグループのユーザ向けに、例えばサイト内のメンバー限定エリアへの アクセスを提供したり、メンバーだけに e-mail メッセージを送るといった、特別 な処理を行うコードを書けます。

メッセージ (Message)

メッセージシステムは、任意のユーザ宛のメッセージをキューしておく軽量な方法 です。

メッセージは User に関連づけられます。 メッセージには有効期限やタイムスタンプの概念はありません。

メッセージは Django admin で何らかの処理の成功を知らせる際に使われています。 例えば、 "The poll Foo was created successfully." はメッセージで実現さ れています。

メッセージの API は単純です:

models.User.message_set.create(message)

メッセージの追加には、 user_obj.message_set.create(message='message_text') を使います。

メッセージの取得と削除には、 user_obj.get_and_delete_messages() を使います。このメソッドは、該当ユーザのキューに溜っている Message オブジェクトがあれば、リストにして返し、キュー内のメッセージを削除しま す。

このビューの例では、システムはプレイリストの作成後に表示されるメッセージを 保存します:

def create_playlist(request, songs):
    # Create the playlist with the given songs.
    # ...
    request.user.message_set.create(message="Your playlist was added successfully.")
    return render_to_response("playlists/create.html",
        context_instance=RequestContext(request))

RequestContext を使うと、現在のログインユー ザとそのメッセージを テンプレート変数 {{ messages }} として使えます。メッセージを表示するためのテンプレートコー ド例を示します:

{% if messages %}
<ul>
    {% for message in messages %}
    <li>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

RequestContextget_and_delete_messages() を背後で呼 び出すので、メッセージは表示されなくても消去されることに注意してください。

最後に、このメッセージフレームワークはユーザデータベースに登録されているユー ザに対してしか動作しないことに注意して下さい。匿名ユーザにメッセージを送る には、 セッションフレームワーク を使って下さい。

他の認証データソースを使う

ほとんどのケースでは、 Django についてくる認証メカニズムで十分のはずですが、 場合によっては別の認証データソース (authentication source) をフックしたい、 すなわち、Django 外のユーザ名やパスワードデータや認証メソッドを使いたいよう なケースもあることでしょう。

例えば、会社が LDAP 構成を使って社員のユーザ名やパスワードを管理していると しましょう。ネットワーク管理者にとっても、またユーザ自身にとっても、 LDAP とDjango ベースのアプリケーションの双方で別々のアカウントを維持するのはいさ さか骨の折れる作業です。

こうした状況を扱うために、 Django の認証システムは別の認証ソースをプラグイ ンできるようになっています。 Django がデフォルトで使っているデータベースの スキームをオーバライドしたり、デフォルトのシステムを他のシステムと並列して 動作させたりできます。

他の認証バックエンドを指定する

舞台裏では、 Django は認証に使う「認証バックエンド」のリストを維持していま す。前述の「ユーザをログインさせる」で説明したように django.contrib.auth.authenticate() を呼び出すと、Django は全ての認 証バックエンドにわたって認証テストを試みます。最初の認証メソッドに失敗する と次の認証バックエンド、という具合にして、認証に成功しない限り、全てのバッ クエンドを試すまで続けます。

認証に使うバックエンドのリストは AUTHENTICATION_BACKENDS 設定に 指定します。この値は Python モジュールパス名からなるタプルで、認証方法を実 装したクラスの名前を指定します。認証クラスは Python パス上のどこにあっても かまいません。

デフォルトでは、 AUTHENTICATION_BACKENDS の値は:

('django.contrib.auth.backends.ModelBackend',)

に設定されています。このクラスは、 Django のユーザデータベースをチェックす る認証スキームです。

AUTHENTICATION_BACKENDS の順番には意味があり、同じユーザ名とパス ワードが複数のバックエンドで有効な値であったとしても、 Django は最初にユー ザ名とパスワードがマッチした時点で認証処理を停止します。

認証バックエンドを作成する

認証バックエンドの実体は、 get_user(user_id)authenticate(**credentials) という二つのメソッドを実装したクラスです。

get_user メソッドはユーザ名、データベース ID などを表す引数 user_id をとり、対応する User オブジェクトを返します。

authenticate メソッドは証明情報、すなわちユーザ名とパスワードなどをキー ワード引数の形で受け取ります。ほとんどの場合、以下のような形式をとります:

class MyBackend:
    def authenticate(self, username=None, password=None):
        # Check the username/password and return a User.

以下のようにトークンに対する認証を行うようにも書けます:

class MyBackend:
    def authenticate(self, token=None):
        # Check the token and return a User.

どちらの方法でも、 authenticate は受け取った証明情報をチェックし、証明 情報が有効な場合、対応する User オブジェクトを返さねばなりません。証明 情報が無効なら、 None を返します。

Django の admin システムは、冒頭で説明した Django の User オブジェクト と強くカップリングしています。従って、今のところ自作の認証バックエンドを扱 うには、 (LDAP ディレクトリや外部の SQL データベースなどのような) 別のバッ クエンド上のユーザに対して Django の User オブジェクトを生成するのがベ ストです。あらかじめスクリプトを書いておいてもよいですし、ユーザが最初にロ グインした際に、 authenticate メソッドでその処理を行うようにしてもよい でしょう。

以下に示すバックエンドの例では、 settings.py ファイルに定義されたユーザ 名とパスワードに対して認証を行い、ユーザが最初に認証を行ったときに User オブジェクトを生成します:

from django.conf import settings
from django.contrib.auth.models import User, check_password

class SettingsBackend:
    """
    Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.

    Use the login name, and a hash of the password. For example:

    ADMIN_LOGIN = 'admin'
    ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
    """
    def authenticate(self, username=None, password=None):
        login_valid = (settings.ADMIN_LOGIN == username)
        pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
        if login_valid and pwd_valid:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                # Create a new user. Note that we can set password
                # to anything, because it won't be checked; the password
                # from settings.py will.
                user = User(username=username, password='get from settings.py')
                user.is_staff = True
                user.is_superuser = True
                user.save()
            return user
        return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

カスタムのバックエンドでパーミッションを扱う

カスタムの認証バックエンドから、独自のパーミッションを提供できます。

認証バックエンドがパーミッション照会のための関数 (get_group_permissions(), get_all_permissions(), has_perm(), および has_module_perms()) をサポートして いる場合、ユーザモデルはパーミッションの照会をバックエンドに移譲します。

あるユーザに付与されるパーミッションの集合は、全てのバックエンドの返しうる パーミッションのスーパーセットです。すなわち、 Django はいずれかのバックエ ンドのパーミッションを、どのユーザにも付与できます。

前述の単純なバックエンドで、万能の管理ユーザを作る方法は、以下のようにとても 簡単です:

class SettingsBackend:

    # ...

    def has_perm(self, user_obj, perm):
        if user_obj.username == settings.ADMIN_LOGIN:
            return True
        else:
            return False

この書き方だと、上の例でアクセスを認可されたユーザにはあらゆるパーミッショ ンが許されます。バックエンドの認証関数はユーザオブジェクトを引数にとります。 また、ユーザオブジェクトの代わりに、 User のコンストラクタと同じ引数も指定 できます。

認可の API は、 django/contrib/auth/backends.py で実装されています。この バックエンドはデフォルトのバックエンドであり、ほとんどの場合 auth_permission にパーミッションを問い合わせます。