revision-up-to: | 8961 (1.0) |
---|
Django にはユーザ認証システムがついてきます。 Django のユーザ認証システムは、 ユーザアカウント、グループ、パーミッションとクッキーベースのユーザセッショ ンを扱えます。このドキュメントでは、ユーザ認証の仕組みについて説明します。
認証システムは以下の要素から成り立っています:
認証のサポートは Django アプリケーションとして django.contrib.auth にバ ンドルされています。インストールするには、以下のようにします:
django-admin.py startproject が生成するデフォルトの settings.py ファイルの INSTALLED_APPS には、簡便のため 'django.contrib.auth' が最初から入っています。この場合は、単に manage.py syncdb するだけでかまいません。 manage.py syncdb はその都度必要なものだけをインストールするので、 何度実行してもかまいません。
syncdb コマンドは必要なデータベーステーブルを作成し、インストー ル済みのアプリケーションで必要な全てのパーミッションオブジェクトを作成しま す。また、最初に実行したときには、ユーザにスーパユーザアカウントを作成する よう促します。
これだけで、認証サポートを使えるようになります。
User objects have the following fields:
User オブジェクトには groups と user_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 オブジェクトには以下のカス タムメソッドがあります:
ユーザにパスワード未設定のマークをつけます。パスワード未設定の状態 は、パスワードが空の文字列である状態と区別されます。パスワード未設 定状態のユーザに対して check_password() を呼び出 すと、決して True を返しません。このメソッドは User オブジェクトを直接保存し ません。
この機能は、 LDAP ディレクトリのような外部の認証ソースを使ってアプ リケーションの認証を行いたい場合に必要です。
ユーザに対して set_unusable_password() を 呼び出し、パスワードが未設定状態であれば False を返します。
User モデルには、以下のヘルパ関数 を備えたマネジャがあります。
ユーザを生成して保存し、生成された User を返します。 username, email および password は指定した値にな り、 is_active は True に設定されます。
パスワードを指定しなかった場合、 set_unusable_password() を 呼び出します。
使い方は ユーザの作成 を参照してください。
ユーザを作成する一番基本的な方法は、オブジェクトマネージャの 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 (デフォルト) または md5 、 crypt のいずれか で、それぞれパスワードの一方向ハッシュ化アルゴリズムを表します。 salt は生 のパスワード文字列からハッシュを生成するときに味付け (salt) しておくための ランダムな文字列です。 crypt のサポートは、 Python の標準モジュール crypt がサポートされている環境だけで有効です。また、 crypt のサポー トは開発版の Django でのみ利用できます。
例えば:
sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4
User.set_password() および User.check_password() set_password() および関数は、これら の値の設定やチェックを背後で行っています。
バージョン 0.90 のような以前の Django では、パスワードソルトなしの単純な MD5 ハッシュを使っていました。この形式は、以前のバージョンとの互換性を持た せるためにまだサポートしています。ただし、古いパスワードのユーザに対する check_password() が成功すると、パ スワードは自動的に新しい形式に変換されます。
django.contrib.auth.models.AnonymousUser は django.contrib.auth.models.User と同じインタフェースを実装した クラスですが、以下の点で User と異 なります:
おそらく、実践上意識して AnonymousUser オブジェクトを使う必要はないはずです。とはいえ、匿名ユーザは次節で述べるよ うな形で Web リクエストで使われています。
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 に以下の内容をドット区切りの文字列で指定しま す:
例えば、プロファイルモデルが UserProfile という名前のクラスで、 accounts というアプリケーションで定義されているなら、設定値は以下のよう になるでしょう:
AUTH_PROFILE_MODULE = 'accounts.userprofile'
上記の方法でユーザプロファイルモデルを定義して指定すると、ユーザオブジェ クトには get_profile() というメソッ ドが付加されます。このメソッドは、ユーザに関連付けられているプロファイルモ デルのインスタンスを返します。
さらに詳しい情報は、 Django book の 12 章 を参照してください。
ここまでのドキュメントは、認証関連のオブジェクトを操作するための低水準の API について扱ってきました。より高水準の API では、 Django はこれらの認証フ レームワークを リクエストオブジェクト シ ステム内にフックできます。
まず、 SessionMiddleware およ び AuthenticationMiddleware を MIDDLEWARE_CLASSES 設定に追加して、これらのミドルウェアをインス トールします。詳しくは セッションのドキュメント を参照してください。
ミドルウェアをインストールしたら、ビューから request.user にアクセスできるように なります。 request.user は現在ログイ ンしているユーザの User オブジェクトを 表します。ユーザがログインしていなければ、 request.user は AnonymousUser のインスタンスになります (前節を参照してください)。ログインユーザと匿名ユーザは、 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() を使ってください。この関数 は二つのキーワード引数、 username と password をとり、ユーザ名 に対してパスワードが有効であった場合に 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() を使ってください。この関数は 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 オブジェクトに、そのユーザが 認証バックエンドによって正しく認証されたことを示す属性を付加します。 (詳しくは 認証バックエンドのドキュメント を参照してください) この情報が後でログインの処理で必要だからです。
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() は エラーを送出しないことに注意してください。
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() デコレータを使え ます:
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): # ...
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 に適切な Django のビュー関数を対応づけておかねばなりません。例えば URLconf に以下の ような行を設定します:
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
django.contrib.auth.views.login は以下のような処理を行います:
開発者は registration/login.html という名前のテンプレート上でログイ ンフォームを提供せねばなりません。 Django はこのテンプレートに、以下の 3 つのテンプレートコンテキスト変数を渡します:
form: ログインフォームを表現する Form オブジェクトです。 Form オブジェクトの詳細 は forms のドキュメント を参照してく ださい。
next: ログイン成功後にリダイレクトされる先の URL です。 URL にはクエリ文字列を含めてかまいません。
site_name: SITE_ID によって決定される現在の Site` の名前です。
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 ビューの他にも便利なビューをいくつか提供してい ます:
ユーザをログアウトさせます。
オプション引数:
テンプレートコンテキスト:
ユーザをログアウトさせてから、ログインページにリダイレクトします。
オプション引数:
ユーザがパスワードを変更できるようにします。
オプション引数:
テンプレートコンテキスト:
ユーザがパスワードを変更した後のページを表示するためのビューです。
オプション引数:
ユーザがパスワードをリセットできるようにします。また、新たなパスワード をメールで送信します。
オプション引数:
テンプレートコンテキスト:
ユーザがパスワードをリセットした後のページを表示するためのビューです。
オプション引数:
ログインページにリダイレクトし、ログインに成功したら別の URL に戻れるよ うにするためのビューです。
必須の引数:
オプション引数:
組み込みビューを使いたくないけれども、フォームクラスを書かずに済ませたい場 合のために、認証システムでは組み込みのフォームをいくつか提供しています:
特定のパーミッションやその他のテストの結果に応じたアクセスの制限には、前節 で説明したの本質的に同じことをします。
一番簡単な方法は、ビュー内で直接 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.")
# ...
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): # ...
あるユーザが特定のパーミッションを有しているかのチェックは、比較的よく ある操作なので、 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 です。
Django には単純なパーミッション機構がついてきます。このパーミッション機構は 特定のユーザやユーザのグループに対してパーミッションを結びつける手段を提供 します。
パーミッション機構は Django の admin サイトでも使われていますが、自作のコー ド内でも自由に使えます。
パーミッションはオブジェクトインスタンスごとではなく、オブジェクトの型ごと にグローバルに設定されます。例えば、「Mary はニュース記事を変更できる」のよ うには書けますが、現状では、「Mary はニュース記事を変更できる。ただし彼女が 書いた分だけ」とか、「Mary はある状態にある記事か、ある日時に出版されたか、 ある ID の記事だけを変更できる」のようには書けません。後者の機能については は、現在 Django の開発者達が議論中です。
INSTALLED_APPS 設定に django.contrib.auth を追加している場合、 インストールされている全てのアプリケーションのモデルについて、追加 (add)、 変更 (change)、および削除 (delete) というデフォルトのパーミッションが作成さ れます。
これらのパーミッションは、 manage.py syncdb を実行した ときに生成されます。厳密には、 django.contrib.auth を INSTALLED_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 を実行したときに追 加のパーミッションを追加することだけです。
Permission オブジェクトには以下のフィー ルドがあります:
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 %}
グループは、パーミッションを適用するユーザのカテゴリを作ったり、一連のユー ザに何らかのラベルを適用するための汎用的な手段です。一人のユーザは複数のグ ループに所属できます。
グループに所属したユーザは、そのグループに許可されているパーミッションを自 動的に得ます。例えば、 Site editors というグループに can_edit_home_page というパーミッションをがあれば、そのグループに属する ユーザはみな, can_edit_home_page のパーミッションを持ちます。
パーミッションだけではなく、グループはユーザをカテゴリに分けてラベルを付け たり、機能を拡張したりできます。例えば、 '特別なユーザ' のグループを作 成して、そのグループのユーザ向けに、例えばサイト内のメンバー限定エリアへの アクセスを提供したり、メンバーだけに e-mail メッセージを送るといった、特別 な処理を行うコードを書けます。
メッセージシステムは、任意のユーザ宛のメッセージをキューしておく軽量な方法 です。
メッセージは User に関連づけられます。 メッセージには有効期限やタイムスタンプの概念はありません。
メッセージは Django admin で何らかの処理の成功を知らせる際に使われています。 例えば、 "The poll Foo was created successfully." はメッセージで実現さ れています。
メッセージの API は単純です:
メッセージの追加には、 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 %}
RequestContext は get_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 にパーミッションを問い合わせます。
Aug 31, 2012