revision-up-to: | 17812 (1.4) |
---|
Django は匿名セッション (anonymous session) を完全にサポートしています。 セッションフレームワークを使うと、任意のデータをサイト訪問者単位 (per-site-visitor) で保存したり取得したりできます。セッションフレームワーク はサーバ側にデータを保存し、クッキーの送受信操作を抽象化します。クッキーに はセッション ID だけが保存され、データ自体は送受信されません。 ( クッキーベースのバックエンド を使うことなしには)
セッション機能は ミドルウェア として実装されていま す。
セッションを有効にするには、以下の作業が必要です:
MIDDLEWARE_CLASSES
を編集して、
'django.contrib.sessions.middleware.SessionMiddleware'
を入れます。 django-admiin.py startproject
の作成するデフォルトの
settings.py
では SessionMiddleware
が有効になっています。セッション機能を必要としないのなら、
MIDDLEWARE_CLASSES
から SessionMiddleware
の行を削り、
INSTALLED_APPS
からも 'django.contrib.sessions'
を削って下さい。セッションを無効にすると、ほんのわずかだけオーバヘッド
を軽減できます。
デフォルトでは、 Django はセッションをデータベースに
(django.contrib.sessions.models.Session
モデルを使って) 保存します。こ
の仕様は便利ではありますが、場合によっては、データベース以外の場所、ファイ
ルシステムやキャッシュ上にセッションデータを保存する方が高速です。
もし、データベースバックエンドセッション(database-backend session)を使いたけれ
ば、 INSTALLED_APPS
セッティングに 'django.contrib.sessions'
を
加える必要があります。
一度、 Django の manage.py syncdb
を走らせて、データベースを構成している
と、テーブルが一つセッションデータを保存するために使われています。
パフォーマンスを求めるなら、キャッシュベースのセッションバックエンドを使う のがよいでしょう。
Django のキャッシュシステムにセッションデータを保存するには、まずキャッシュ を設定しておく必要があります。詳しくは キャッシュのドキュメント を参照してください。
Warning
Memcached をキャッシュバックエンドとして使っているなら、キャッシュベー スのセッションを使うべきです。ローカルメモリ型のキャッシュバックエンド は十分な時間データを保持できないので、よい選択肢とはいえません。また、 ファイルやデータベースによるキャッシュバックエンドを使っている場合、何 もかもをキャッシュに放り込むより、直接ファイルやデータベースからデータ を出力する方がはるかに高速です。
一度キャッシュが設定されていれば、キャッシュにデータを保存する二つの方法が 選べます。
SESSION_ENGINE
を
"django.contrib.sessions.backends.cache"
に、設定すると、シンプルにセッションの保存がキャッシングできます。セッション
データは、直接キャッシュの中に保存されます。しかし、セッションデータは
永続的ではありません。キャッシュされたデータはキャッシュが一杯になるか、
キャッシュサーバーが再起動された時に消去されてしまいます。SESSION_ENGINE
を
"django.contrib.sessions.backends.cached_db"
に設定してください。
これは、ライトスルーキャッシュを用います(write-through cache)。
全ての書き込みがキャッシュへといき、またデータベースにも書き込まれます。
セッションは、キャッシュの中にデータが準備されていなければ、データベース
しか読みません。両方のセッションの保存はどちらも十分に高速ですが、シンプルキャッシュは
永続性を放棄した結果、より早くなっています。ほとんどのケースで、 cached_db
バックエンドも必要な程度の早さを発揮しますが、少しでも早さを求めるなら、
そしてセッションデータが時とともに消去されていくのをよしとするなら、
cache
バックエンドが適しているケースでしょう。
ファイルベースのセッションを使うには、 SESSION_ENGINE
設定を
"django.contrib.sessions.backends.file"
にします。
また、必要に応じて SESSION_FILE_PATH
も設定してください
(デフォルト値は tempfile.gettempdir()
の戻り値で、たいていは /tmp
です)。
Web サーバが SESSION_FILE_PATH
の場所にファイルの読書き権限を持っているか
確かめてください。
リリースノートを参照してください
クッキーベースセッションを使うには、 SESSION_ENGINE
を
"django.contrib.sessions.backends.signed_cookies"
に設定します。
セッションデータは、 cryptographic signing
と SECRET_KEY
設定へと Django ツールを使って保存されます。
Note
SESSION_COOKIE_HTTPONLY
設定を True
にすると、
JavaScript から、保存されたデータを改ざんすることを妨げることが
できるのでお勧めしています。
Warning
セッションデータは認証されていますが、暗号化されていません
クッキーバックエンドを使うと、セッションデータはクライアントから 読むことが出来ます。
MAC ( Message Authentication Code )は、クライアントからのデータの変更から データを守るのに使われます、つまりセッションデータは改ざんされる時に無効 化されるということです。同じような無効化は、クライアントが保存している クッキー(すなわち、ユーザのブラウザが保存しているもの)が、全て保存されない 場合と、データが欠落してしまった場合に起こります。 Django はデータを 圧縮していますが、それは common limit of 4096 bytes を超過しています。
最新である保証がない
MAC がデータの信頼性と(これはあなたのサイトが生成します)
データの一貫性(全てがそこにあり、全てが正しいかどうか)を保証する一方、
MAC はデータの最新性を保証しません。すなわち、クライアントに送信した
最後のものが、返ってきているということです。これは、セッションデータが
いくつか用いていることを意味します。クッキーバックエンドは
反射攻撃 に耐えて開くだろうということです。
SESSION_COOKIE_AGE
よりもクッキーが古い場合、クッキーは ‘stale’ としてのみ検出されます。
パフォーマンス
最後に、大容量のクッキーは、 サイトのスピード に影響を与えます。
SessionMiddleware
を有効にすると、各々の
HttpRequest
オブジェクト(Django ビュー関数の最初の引数)
は辞書ライクオブジェクトの属性 session
を持つようになります。
この属性は読み書き可能です。
ビューのどの部分でも request.session
で読み書き可能です
複数回の編集・変更が可能です。
backends.base.
SessionBase
¶これは、全てのセッションオブジェクトのベースクラス(基底クラス)です。 通常のディクショナリのメソッドをサポートしています。
__getitem__
(key)¶例: fav_color = request.session['fav_color']
__setitem__
(key, value)¶例: request.session['fav_color'] = 'blue'
__delitem__
(key)¶例: del request.session['fav_color']
セッションデータ中に key
に対応する値がない場合には KeyError
を送出します。
__contains__
(key)¶例: 'fav_color' in request.session
get
(key, default=None)¶例: fav_color = request.session.get('fav_color', 'red')
pop
(key)¶例: fav_color = request.session.pop('fav_color')
keys
()¶setdefault
()¶clear
()¶これは、三つのメソッドを持っています:
flush
()¶現在のセッションデータをデータベースから削除し、後でクッキーに入れて
ユーザに送り返すために新たなセッションキーを生成します。ユーザの使っ
ているブラウザに、以前のセッションデータにアクセスさせたくない場合に
使います (例えば django.contrib.auth.logout()
で呼び出されま
す)。
テストクッキーを設定して、ユーザのブラウザがクッキーをサポートしてい るかどうかを調べられるようにします。クッキーの動作仕様上、次にブラウ ザがリクエストを送信してくるまでテストは行えません。詳しくは後述の 「 テストクッキーを設定する 」を参照してください。
ユーザのブラウザがテストクッキーを受け入れたかどうかに応じて True
または False
を返します。クッキーの動作仕様上、あらかじめ別のペー
ジリクエストで set_test_cookie()
を呼び出しておかねばなりません。
後述の「 テストクッキーを設定する 」を参照してください。
テストクッキーを削除します。後始末に使って下さい。
set_expriry
(value)¶セッションの有効期限をセットします。渡せる値には、以下のバリエーションが あります:
value
に整数を渡すと、セッションがアクティブでないまま
value
秒間経った時点で有効期限が切れます。例えば、
request.session.set_expiry(300)
とすると、セッションの有
効期限は 5 分で切れます。value
に datetime
や timedelta
オブジェクトを渡す
と、セッションの有効期限は指定日・時刻に切れます。value
に 0
を渡すと、ユーザセッションクッキーの有効期
限は、ブラウザを閉じた時点で切れます。value
に None
を渡すと、セッションの有効期限はグロー
バルに設定されているセッションポリシーに戻されます。セッションの読み込みはアクションの目的が満たされているかは考慮しません。 セッションの満了は、セッションが最後に 変更された かをもとに計算されて います。
get_expiry_age
()¶セッションの有効期限が切れるまでの秒数を返します。セッションの有効期
限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限
としている場合) は、 settings.SESSION_COOKIE_AGE
と等しい値です。
get_expiry_date
()¶セッションの有効期限が切れるまでの日数を返します。セッションの有効期
限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限
としている場合) は、 SESSION_COOKIE_AGE
秒に相当する日数
です。
get_expire_at_browser_close
()¶ユーザのセッションクッキーの有効期限がブラウザを閉じるまでに設定され
ていれば True
を、そうでなければ False
を返します。
request.session
のキーには通常の Python 文字列を使って下さい。と
はいえ、これは厳格な掟 (hard-and-fast rule) ではなく単なる規約です。request.session
を新たなオブジェクトでオーバライドしたり、属性を
いじってはなりません。Python 辞書型のように扱って下さい。以下の簡単なビューの例では、ユーザがコメントをポストした後に
has_commented
という変数を True
に設定しています。これにより、一人
のユーザに一つのコメントを何度もポストさせないようにします:
def post_comment(request, new_comment):
if request.session.get('has_commented', False):
return HttpResponse("You've already commented.")
c = comments.Comment(comment=new_comment)
c.save()
request.session['has_commented'] = True
return HttpResponse('Thanks for your comment!')
以下のビューでは、「メンバ」をサイトにログインさせます:
def login(request):
m = Member.objects.get(username__exact=request.POST['username'])
if m.password == request.POST['password']:
request.session['member_id'] = m.id
return HttpResponse("You're logged in.")
else:
return HttpResponse("Your username and password didn't match.")
そして下の例では、上の例で login()
したメンバをログアウトさせます:
def logout(request):
try:
del request.session['member_id']
except KeyError:
pass
return HttpResponse("You're logged out.")
実際には、標準の django.contrib.auth.logout()
は、うっかりデータが漏洩
してしまうのを防ぐために、 request.session
の
flush()
を呼び出しています。
上の例はセッションオブジェクトの仕組みを説明するためのもので、完全な
logout()
の実装ではありません。
利便性のために、 Django ではユーザのブラウザがクッキーを受け入れるかどうか
を調べるための簡単な方法を提供しています。ビュー内で request.session
の
set_test_cookie()
を呼び出しておき、
それ以後のビュー、すなわち別のビュー呼び出しで
test_cookie_worked()`()
を呼び出すようにしてください。
set_test_cookie()
と test_cookie_worked()
が別々のビュー呼び出しに
分離されるのは不恰好ですが、これはクッキーの動作上仕方のないことです。ある
ブラウザに対して一度クッキーを設定しても、そのブラウザが次にリクエストを送
信するまではクッキーを受け入れたかどうかを確かめる術はないのです。
テストが終わったら、 delete_test_cookie()
を呼び出して後始末をしておくのがよいでしょう。
クッキーの動作テストが終わった時点で、この関数を呼び出して下さい。
典型的な使用例を以下に示します:
def login(request):
if request.method == 'POST':
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponse("You're logged in.")
else:
return HttpResponse("Please enable cookies and try again.")
request.session.set_test_cookie()
return render_to_response('foo/login_form.html')
API を使うと、ビューの外からセッションデータを操作できます:
>>> from django.contrib.sessions.backends.db import SessionStore
>>> import datetime
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
>>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10)
>>> s['last_login']
datetime.datetime(2005, 8, 20, 13, 35, 0)
>>> s.save()
もし、 session_key
が与えられていなければ、自動で生成されます。:
>>> from django.contrib.sessions.backends.db import SessionStore
>>> s = SessionStore()
>>> s.save()
>>> s.session_key
'2b1189a188b44ad18c35e113ac6ceead'
django.contrib.sessions.backends.db
バックエンドを使っている場合、各セッ
ションは Django のモデルインスタンスで表現されています。 Session
モデル
は django/contrib/session/models.py
で定義されています。 Session
は
通常のモデルなので、通常の Django データベース API でアクセスできます:
>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)
セッション情報の辞書を取得するには get_decoded()
を呼び出す必要があるの
で注意して下さい。というのも、セッション情報はエンコードされた形式で保存さ
れているからです。
>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}
デフォルトでは、 Django はセッション情報が変更された場合、すなわちセッショ ン情報の入った辞書に値を代入したり、値を削除した場合にのみ、セッションデー タベースを保存します:
# セッションデータは変更されたものとみなされます
request.session['foo'] = 'bar'
# セッションデータは変更されたものとみなされます
del request.session['foo']
# セッションデータは変更されたものとみなされます
request.session['foo'] = {}
# 落とし穴: request.session ではなく request.session['foo'] の変更なの
# で、セッションデータは変更されたものとみなされません。
request.session['foo']['bar'] = 'baz'
上の例の最後のケースでは、セッションオブジェクトに内容が変更されたことを明
示的に教えねばなりません。変更の通知は modified
属性で行います:
request.session.modified = True
この振舞いを変更したければ、 SESSION_SAVE_EVERY_REQUEST
設定を True
に設定してください。 SESSION_SAVE_EVERY_REQUEST
を True
にすると、
Django はリクエスト一つ一つに対してセッションを保存します。
セッションクッキーはセッションが作成されたり変更されたりした場合にのみ送信
されることに注意してください。 SESSION_SAVE_EVERY_REQUEST
を True
にすると、リクエストごとに必ずセッションクッキーを送信するようになります。
同様に、セッションクッキーの expires
部分もセッションクッキーの送信ごと
に更新されます。
SESSION_EXPIRE_AT_BROWSER_CLOSE
設定を使うと、セッションフレームワーク
に、ブラウザアクセス単位のセッションと永続的セッションのどちらを使わせるか
を指定できます。
デフォルトでは、 SESSION_EXPIRE_AT_BROWSER_CLOSE
は False
に設定さ
れています。これはセッションクッキーが SESSION_COOKIE_AGE
の間だけブラ
ウザに保存されることを示します。ユーザがブラウザを起動するたびにログインし
なくてもすむようにしたければ、この設定を使ってください。
SESSION_EXPIRE_AT_BROWSER_CLOSE
を True
にすると、 Django はブラウ
ザアクセス単位のクッキー、すなわちユーザがブラウザを閉じると有効期限が切れ
るようなクッキーを使うようになります。ブラウザを起動するたびにユーザにログ
イン操作を行わせたい場合、この設定を使ってください。
この設定は、グローバルに有効なデフォルト値です。
request.session
のメソッドである「 ビューの外でセッションを使う 」の節で解説した、
set_expiry()`()
を使えば、セッション単位で有効期限をオーバ
ライドできます。
セッションデータは django_session
データベーステーブル上に蓄積されます
が、 Django はセッションテーブルを自動的に清掃 しません。 つまり、期限切
れの (expired) セッションデータを正しい判断基準の下に削除するのは、アプリケー
ション開発者であるあなた自身の仕事なのです。
この問題を理解するには、ユーザがセッションを使ったときに何が起きているかを
考える必要があります。ユーザがログインすると、 Django は django_session
データベーステーブルにレコードを 1 行追加します。セッションデータが変更され
る度に、このレコード行は更新されてゆきます。ユーザが手動でログアウトすれば、
レコード行は削除されますが、ユーザがログアウト操作を しなかった場合 には、
レコード行は削除されません。
Django は、クリーンアップ用のアクション、 django-admin.py cleanup
を提
供しています。このスクリプトはセッションテーブルの全てのエントリの中から、
expire_date
の値が過去を指しているものを除去します。もちろん、お使いの
アプリケーションが要求する仕様が異なる場合には、別のスクリプトを用意する必
要があるでしょう。
Django 設定ファイル には、セッションの振舞いを操作す るための設定がいくつかあります:
デフォルト値: django.contrib.sessions.backends.db
Django がセッションデータを保存する方法を指定します。利用できる値は以下の通 りです:
'django.contrib.sessions.backends.db'
'django.contrib.sessions.backends.file'
'django.contrib.sessions.backends.cache'
'django.contrib.sessions.backends.cached_db'
'django.contrib.sessions.backends.signed_cookies'
詳しくは セッションエンジンの設定 を参照してください。
デフォルト値: None
セッションクッキーを使うドメインです。クロスドメインのクッキーを使う場合に
は ".lawrence.com"
といった値に、通常のドメイン内クッキーの場合には
None
を指定します。
Default: True
セッションクッキーで HTTPOnly フラグを使うかどうかです。もし、これが
True
になっている場合は、クライアントサイドの JavaScript はセッション
クッキーにアクセスすることができなくなります。
HTTPOnly は、Set-Cookie HTTP レスポンスヘッダーの中に含まれています。 これは RFC 2109 のクッキー標準の一部ではありません、これは全ての ブラウザで重んじられているわけではありません。しかし、これが重視されて いれば、クッキーデータをクライアントサイドのスクリプト攻撃からデータを保護 し、リスクを軽減します。
Default: '/'
このパスはセッションクッキーにセットされます。これは、 Django のインストール されている URL パスか、そのパスの親にマッチします。
これは、同じホストネームで複数の Django インスタンスを走らせる時に便利です。 異なるクッキーパスを用いれるので、インスタンスごとに自身のセッションクッキーを 見ることになります。
デフォルト値: False
セッションクッキーにセキュアなクッキーを使うかどうかを決めます。この値を
True
に設定すると、クッキーは “セキュア” にマークされます。クッキーがセ
キュアにマークされると、ブラウザによっては HTTPS 接続でのみクッキーを転送す
るようになります。
デフォルト値: False
リクエストごとにセッションデータを保存するかどうかを決めます。この値が
False
(デフォルト) の場合、セッションデータの保存は内容が変更された場合、
すなわちセッションデータ辞書に値を設定したり、値を削除したりした場合だけに
なります。
pickle モジュール
を参照してください。django_session
という名前のデータベーステーブルに
保存されます。Django のセッションフレームワークは完全なクッキーベースであり、クッキー以外 の情報を扱いません。従って、 PHP のように URL にセッション ID を入れる方法 を最後の手段に残したりはしていません。これは設計上の意図的な決定です。とい うのも、URL にセッション ID を含めると、みっともない URL になるだけでなく、 “Referer” ヘッダを使ってセッション ID を盗まれるという脆弱性を招くからです。
Oct 26, 2017