Django は、匿名のセッションをフルサポートしています。このセッションフレームワークを使えば、任意のデータを、サイトの訪問者ごとに保存し、取得することができます。データはサーバー側に保存され、クッキーの送受信によって抽象化します。クッキーには、データそのものではなくセッション ID が書かれています ( クッキーベースのバックエンド を使用しない限り)。
セッションは、 ミドルウェア の1つを使って実装されています。
セッションの機能を有効にするには、次のように設定を行います。
MIDDLEWARE
設定を編集し 'django.contrib.sessions.middleware.SessionMiddleware'
を含むようにする。 django-admin startproject
で作られるデフォルトの settings.py
は SessionMiddleware
が有効化されています。セッションを使いたくない場合は、 MIDDLEWARE
内の SessionMiddleware
行と INSTALLED_APPS
内の 'django.contrib.sessions'
を削除しても構いません。これで、オーバーヘッドが少しだけ短縮されます。
デフォルトでは、Django はセッションを、(django.contrib.sessions.models.Session
モデルを用いて) データベースに保存します。これは便利ですが、セットアップによってはセッションのデータを他の場所においたほうが高速化できる場合があります。そのため、Django はセッションデータをファイルシステムやキャッシュに保存するように設定することができます。
データベースを使った (database-backed) セッションを使いたい場合には、設定ファイルの INSTALLED_APPS
に 'django.contrib.sessions'
を追加する必要があります。
一度インストールの設定をすれば、manage.py migrate
を実行することで、セッションデータを保存する1つのデータベーステーブルをインストールできます。
よいパフォーマンスを発揮するには、キャッシュを使ったセッションバックエンドを利用した方が良いかもしれません。
Django のキャッシュシステムを使ってセッションデータを保存するには、まず初めに、キャッシュの設定を済ませておく必要があります。詳しくは、 キャッシュのドキュメンテーション を読んでください。
警告
You should only use cache-based sessions if you're using the Memcached or Redis cache backend. The local-memory cache backend doesn't retain data long enough to be a good choice, and it'll be faster to use file or database sessions directly instead of sending everything through the file or database cache backends. Additionally, the local-memory cache backend is NOT multi-process safe, therefore probably not a good choice for production environments.
設定ファイルの CACHES
で複数のキャッシュを定義している場合、Django はデフォルトのキャッシュを使用します。他のキャッシュを使用するには、SESSION_CACHE_ALIAS
を使用したいキャッシュの名前に変更します。
キャッシュの設定が完了したら、キャッシュへのデータの保管方法を、次の2つの選択肢から選ぶことができます。
SESSION_ENGINE
を "django.contrib.sessions.backends.cache"
に設定すると、シンプルなキャッシュセッションを保存します。セッションデータはキャッシュに直接保存されることになります。しかし、この場合、セッションデータが永続化されず、キャッシュがいっぱいになったりキャッシュサーバが再起動した際に、一度キャッシュされていたデータがクリアされてしまうことがあります。SESSION_ENGINE
を "django.contrib.sessions.backends.cached_db"
に設定します。こちらは、書き込み透過な (write-through) キャッシュを使用します。つまり、キャッシュにデータが書き込まれるのと同時に、データベースにも同じデータが書き込まれます。セッションは、データがキャッシュ上から読み込めない時に限り、データベースからデータを読み込みます。いずれのセッションのデータの保存も非常に高速ですが、シンプルなキャッシュを使用した方が、永続化の処理をしないので、より高速です。ほとんどのケースでは cached_db
バックエンドでも十分高速ですが、パフォーマンスを最重視していて、セッションデータが時間経過で失われてもかまわない場合には、cache
バックエンドを使用すると良いでしょう。
cached_db
セッションバックエンドを使用する場合には、using database-backed sessions に書かれている手順にしたがって、設定を行ってください。
ファイルを使ったセッションを使用するには、SESSION_ENGINE
を "django.contrib.sessions.backends.file"
に設定します。
You might also want to set the SESSION_FILE_PATH
setting (which
defaults to output from tempfile.gettempdir()
, most likely /tmp
) to
control where Django stores session files. Be sure to check that your web
server has permissions to read and write to this location.
クッキーを使ったセッションを使用するには、 SESSION_ENGINE
を "django.contrib.sessions.backends.signed_cookies"
に設定します。セッションデータは、 暗号化署名 のための Django のツールと SECRET_KEY
を使って保存されます。
注釈
保存されたデータに JavaScript からアクセスできないように、SESSION_COOKIE_HTTPONLY
を True
に設定しておくことをおすすめします。
警告
SECRET_KEY が知られてしまい、 PickleSerializer
を使用していた場合、任意のリモートコードが実行可能になってしまいます。
SECRET_KEY
を知っている攻撃者は、偽造したセッションデータを生成して Django のサイトを騙すことができるのみならず、pickle を使ってシリアライズしたデータを送ることで、リモートから任意のコードを実行できてしまいます。
クッキーを使ったセッションを使うときには、リモートからアクセスできるいかなるシステムに対しても秘密鍵が絶対に外に漏れないように、細心の注意を払ってください。
このセッションデータは、署名はされていますが、暗号化はされていません。
クッキーバックエンドを使う時には、セッションデータはクライアントが自由に読むことができます。
A MAC (Message Authentication Code) is used to protect the data against changes by the client, so that the session data will be invalidated when being tampered with. The same invalidation happens if the client storing the cookie (e.g. your user's browser) can't store all of the session cookie and drops data. Even though Django compresses the data, it's still entirely possible to exceed the common limit of 4096 bytes per cookie.
情報が最新であることが保証されません
MAC のおかげで、データの認証性 (データが他のサイトではなく、確実に自分のサイトで作られたものであること) と、完全性 (データが存在し、データが正しいこと) は保証されますが、そのデータが最新のものであることは保証することができません。つまり、クライアントからデータを受け取ったとしても、そのデータがユーザに最後に送った最新のデータであることは保証できないのです。ということは、セッションデータの使い方によっては、クッキーバックエンドでは replay attacks ができてしまうことになります。他のセッションバックエンドでは、サーバー側に各セッションの記録が残るので、ユーザがログアウトした時にそれを無効化できますが、クッキーを使ったセッションの場合には、ユーザがログアウトしてもセッションは無効化されません。したがって、攻撃者がユーザのクッキーを盗めば、たとえユーザがログアウトしていたとしても、そのクッキーを使ってユーザになりすますことができてしまいます。クッキーが「古くなった」と判断できるのは、SESSION_COOKIE_AGE
を過ぎた場合だけだからです。
パフォーマンス
Finally, the size of a cookie can have an impact on the speed of your site.
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, default=__not_given)¶例: fav_color = request.session.pop('fav_color', 'blue')
keys
()¶items
()¶setdefault
()¶clear
()¶また、次のようなメソッドも利用できます。
flush
()¶セッションから現在のセッションデータを削除し、セッションクッキーを削除します。このメソッドは、前回のセッションデータがユーザのブラウザから再びアクセスされないようにするためなどに使います (たとえば、django.contrib.auth.logout()
がこの関数を呼びます)。
set_test_cookie
()¶ユーザのブラウザがクッキーをサポートしているかどうか判定するために、テスト用のクッキーをセットします。クッキーの動作原理により、ユーザが次のページへのリクエストを行わないとこのテストは行えません。詳しい情報については、下の Setting test cookies を読んでください。
test_cookie_worked
()¶ユーザのブラウザがテストクッキーを正しく保存したかどうかに応じて、True
または False
を返します。クッキーの動作原理により、あらかじめ別のページのリクエストとして set_test_cookie()
を呼び出しておく必要があります。詳しい情報については、下の Setting test cookies を読んでください。
delete_test_cookie
()¶テストクッキーを削除します。クッキーをきれいにしておくために使ってください。
get_session_cookie_age
()¶Returns the value of the setting SESSION_COOKIE_AGE
. This can
be overridden in a custom session backend.
set_expiry
(value)¶セッションの有効期限を設定します。以下に挙げるようなさまざまな値を与えることができます。
value
が整数なら、与えられた秒数だけ活動がなかった時にセッションを破棄します。たとえば、request.session.set_expiry(300)
と呼び出せば、5分後にセッションを破棄するように設定できます。value
が datetime
または timedelta
オブジェクトならば、指定された日時に破棄されます。datetime
と timedelta
の値がシリアライズできるのは、PickleSerializer
を使っている場合のみであることに注意してください。value
is 0
, the user's session cookie will expire
when the user's web browser is closed.value
が None
ならば、セッションはグローバルなセッション有効期限ポリシーにしたがって扱われます。セッションの読み込みを行っても、有効期限は延長されません。セッションの有効期限は、セッションが最後に*修正された*時点を基に計算されます。
get_expiry_age
()¶このセッションの有効期限までの残りの秒数を返します。カスタムの有効期限を持たない (または、ブラウザを閉じた時とセットした) セッションの場合、この値は SESSION_COOKIE_AGE
と等しいです。
この関数は 2 つの省略可能なキーワード引数を取ることができます。
modification
: セッションを最後に修正した時刻を datetime
オブジェクトとして与える。デフォルトは現在の時刻。expiry
: セッションの有効期限の情報を datetime
オブジェクト、int
(秒数で)、または None
として与えます。デフォルトの値は、もしあれば、セッションに保存されている set_expiry()
で得られる値、なければ None
です。注釈
This method is used by session backends to determine the session expiry age in seconds when saving the session. It is not really intended for usage outside of that context.
In particular, while it is possible to determine the remaining
lifetime of a session just when you have the correct
modification
value and the expiry
is set as a datetime
object, where you do have the modification
value, it is more
straight-forward to calculate the expiry by-hand:
expires_at = modification + timedelta(seconds=settings.SESSION_COOKIE_AGE)
get_expiry_date
()¶このセッションが破棄される日付を返します。カスタムの有効期限を持たない (または、ブラウザを閉じた時とセットした) セッションに対しては、現在時刻から SESSION_COOKIE_AGE
の秒数までの日付に等しいです。
This function accepts the same keyword arguments as
get_expiry_age()
, and similar notes on usage apply.
get_expire_at_browser_close
()¶Returns either True
or False
, depending on whether the user's
session cookie will expire when the user's web browser is closed.
clear_expired
()¶保存されているセッションから、有効期限が切れているものを削除します。このクラスメソッドは、clearsessions
から呼び出されます。
cycle_key
()¶現在のセッションデータを保持したまま、新しいセッションキーを作成します。django.contrib.auth.login()
は、このメソッドを呼び出すことで、過去のセッションを継続できるようにしています。
デフォルトでは、Django はセッションデータを JSON を用いてシリアライズします。設定ファイルの SESSION_SERIALIZER
に設定すれば、セッションをシリアライズするフォーマットをカスカムできます。 自作のシリアライザを書く に書いた注意書きの通り、JSON によるシリアライズを強く推奨します。 クッキーバックエンドを利用している場合は特に です。
たとえば、セッションデータをシリアライズするために pickle
を使用していた場合の、こんな攻撃のシナリオを考えてみましょう。あなたは 署名したクッキーセッションバックエンド を使用していて、SECRET_KEY
が攻撃者に知られてしまっていたとします (もちろん、これは Django にキーが流出する脆弱性が内在しているというわけではありません)。この時、攻撃者は、セッションに任意の文字列を挿入することができてしまい、このセッションをアンピックすると、サーバ上で任意のコードが実行されてしまいます。このような攻撃は、インターネット上のどこからでも簡単にできてしまいます。クッキーセッションストレージは、クッキーに保存されているデータが勝手に書き換えられないようにクッキーに署名をしていますが、SECRET_KEY
が流出するだけで、リモートからコードを実行されてしまう脆弱性が生まれてしまうのです。
serializers.
JSONSerializer
¶django.core.signing
の JSON シリアライザのラッパーです。基本的なデータ型だけがシリアライズ可能です。
また、JSON は文字列のキーしかサポートしていないので、request.session
に文字列以外のキーを使用してしまうと、次のように期待通りに動いてくれません。
>>> # initial assignment
>>> request.session[0] = 'bar'
>>> # subsequent requests following serialization & deserialization
>>> # of session data
>>> request.session[0] # KeyError
>>> request.session['0']
'bar'
Similarly, data that can't be encoded in JSON, such as non-UTF8 bytes like
'\xd9'
(which raises UnicodeDecodeError
), can't be stored.
JSON によるシリアライズの制限について詳しくは、自作のシリアライザを書く セクションを読んでください。
serializers.
PickleSerializer
¶任意の Python オブジェクトをサポートしますが、上に書いた理由により、このシリアライザを使用すると、攻撃者に SECRET_KEY
が知られた場合に、リモートからコードを実行される脆弱性を生んでしまいます。
Note that unlike PickleSerializer
,
the JSONSerializer
cannot handle
arbitrary Python data types. As is often the case, there is a trade-off between
convenience and security. If you wish to store more advanced data types
including datetime
and Decimal
in JSON backed sessions, you will need
to write a custom serializer (or convert such values to a JSON serializable
object before storing them in request.session
). While serializing these
values is often straightforward
(DjangoJSONEncoder
may be helpful),
writing a decoder that can reliably get back the same thing that you put in is
more fragile. For example, you run the risk of returning a datetime
that
was actually a string that just happened to be in the same format chosen for
datetime
s).
シリアライザのクラスは、必ず次の2つのメソッドを実装しなければなりません。セッションデータのディクショナリをシリアライズする dumps(self, obj)
と、それをデシリアライズする loads(self, data)
の2つです。
request.session
におけるディクショナリのキーとして使うこと。これは慣習のためというよりも、確実で高速にするためのルールです。request.session
を新しいオブジェクトで上書きせず、その属性にアクセスしたり、値をセットしたりしないこと。Python のディクショナリのように扱うこと。次の簡単なビューは、ユーザがコメントを投稿した後で、has_commented
変数を True
に設定します。こうすることで、同じユーザが2回以上コメントできないようにすることができます。
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!')
次の次の簡単なビューでは、サイトの「メンバー (member)」にログインする手続きを行います。
def login(request):
m = Member.objects.get(username=request.POST['username'])
if m.check_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()
を実装しました。
As a convenience, Django provides a way to test whether the user's browser
accepts cookies. Call the set_test_cookie()
method of request.session
in a view, and call
test_cookie_worked()
in a subsequent view --
not in the same view call.
このように set_test_cookie()
と test_cookie_worked()
を分離しなければならないのはちょっと気持ち悪いですが、クッキーの動作原理により、こうするより仕方がないのです。一度ブラウザにクッキーを設定しても、そのクッキーがブラウザに保存されたかどうかを確認するには、ブラウザがもう一度リクエストを行わなければならないからです。
テストクッキーがちゃんと機能していることを確認できたら、delete_test_cookie()
を使ってセッションをきれいにしておくことにしましょう。
以下に、テストクッキーの典型的な使用例を挙げます。
from django.http import HttpResponse
from django.shortcuts import render
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(request, 'foo/login_form.html')
注釈
このセクションの例では、SessionStore
オブジェクトを直接 django.contrib.sessions.backends.db
バックエンドからインポートしています。しかし、実際に自分でコートを書く場合には、以下のようにして、SESSION_ENGINE
が指すセッションエンジンから SessionStore
をインポートすることを考えるべきです。
>>> from importlib import import_module
>>> from django.conf import settings
>>> SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
次のようにして、ビューの外からセッションデータを操作する API が利用可能です。
>>> from django.contrib.sessions.backends.db import SessionStore
>>> s = SessionStore()
>>> # stored as seconds since epoch since datetimes are not serializable in JSON.
>>> s['last_login'] = 1376587691
>>> s.create()
>>> s.session_key
'2b1189a188b44ad18c35e113ac6ceead'
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
>>> s['last_login']
1376587691
SessionStore.create()
is designed to create a new session (i.e. one not
loaded from the session store and with session_key=None
). save()
is
designed to save an existing session (i.e. one loaded from the session store).
Calling save()
on a new session may also work but has a small chance of
generating a session_key
that collides with an existing one. create()
calls save()
and loops until an unused session_key
is generated.
If you're using the django.contrib.sessions.backends.db
backend, each
session is a normal Django model. The Session
model is defined in
django/contrib/sessions/models.py
. Because it's a normal model, you can
access sessions using the normal Django database 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 がセッションデータベースへデータを保存するのは、セッションが修正された時だけ、つまり、ディクショナリ直下の値が代入または削除された時だけです。
# Session is modified.
request.session['foo'] = 'bar'
# Session is modified.
del request.session['foo']
# Session is modified.
request.session['foo'] = {}
# Gotcha: Session is NOT modified, because this alters
# request.session['foo'] instead of request.session.
request.session['foo']['bar'] = 'baz'
上の例の場合、セッションオブジェクトに修正したことを明示的に伝えるためには、modified
属性を設定すれば良いです。
request.session.modified = True
このデフォルトの動作を変更するには、設定ファイルの SESSION_SAVE_EVERY_REQUEST
を True
に設定します。True
に設定すると、Django は1リクエストごとに、セッションをデータベースに保存してくれるようになります。
セッションクッキーが送信されるのは、セッションの作成及び修正時のみであることに注意してください。SESSION_SAVE_EVERY_REQUEST
を True
に設定すると、各リクエストごとにセッションクッキーが送信されるようになります。
同時に、セッションクッキーの expires
部分も、セッションクッキーが送信されるごとに更新されます。
レスポンスステータスコードが 500 の時には、セッションは保存されません。
SESSION_EXPIRE_AT_BROWSER_CLOSE
設定を使うと、セッションフレームワークが、ブラウザ起動中のみ有効なセッションと永続的なセッションのどちらを使うか設定できます。
デフォルトでは、SESSION_EXPIRE_AT_BROWSER_CLOSE
は False
にセットされていて、セッションクッキーは SESSION_COOKIE_AGE
の期間ユーザのブラウザに保持されます。これにより、ユーザはブラウザを開くたびにログインし直さずに済みます。
SESSION_EXPIRE_AT_BROWSER_CLOSE
を True
に設定すると、Django はブラウザ起動中のみ有効なクッキーを使用します。このクッキーは、ブラウザを閉じた瞬間に破棄されます。ユーザがブラウザを開くたびにログインするようにしたい場合には、この設定を利用してください。
この設定はグローバルなデフォルトですが、1セッションごとのレベルで設定を上書きすることができます。その場合には、上の using sessions in views で書いたようにして、request.session
の set_expiry()
メソッドを呼び出してください。
注釈
一部のブラウザ (たとえば Chrome) では、ブラウザを閉じて再度開いてもセッションを継続できるようにする設定が提供されています。場合によっては、この設定が SESSION_EXPIRE_AT_BROWSER_CLOSE
設定を妨げて、ブラウザが閉じてもセションが破棄されないことがあります。SESSION_EXPIRE_AT_BROWSER_CLOSE
を有効にした Django アプリケーションのテストをする時には、この点に注意してください。
ユーザがウェブサイトで新しいセッションを作成した時、セッションデータはセッションストアに溜め込まれます。データベースのバックエンドを使っている場合には、django_session
データベーステーブルが増大し、ファイルバックエンドを使っている場合には、一時ディレクトリのファイル数が増えてゆくでしょう。
この問題を理解するには、データベースバックエンドで起きていることを考えてみてください。ユーザがログインすると、Django は django_session
データベースのテーブルに1行を追加します。Django はセッションのデータが変更されるたびに、この行を更新します。ユーザが手動でログアウトすると、Django はこの行を削除します。しかし、ユーザがログアウト*しなかった*場合には、この行は決して削除されません。同様のプロセスが、ファイルバックエンドの場合にも発生します。
Django は、有効期限の切れたセッションを自動的に削除する機能を提供*しません*。したがって、定期的に有効期限の切れたセッションを削除する仕事は、開発者の手に委ねられています。Django はこの目的のために、クリーンナップ用の管理コマンド clearsessions
を用意しています。たとえば、cron の毎日のジョブに追加するなどの方法で、定期的にこのコマンドを実行することが推奨されています。
キャッシュバックエンドの場合はこの問題が発生しないことに注意してください。キャッシュの場合、不要なデータは自動的に削除されるようになっているからです。しかし、クッキーバックエンドの場合はそうではありません。セッションデータはユーザのブラウザに保存されるからです。
以下の Django の設定 を使うと、セッションの振る舞いをコントロールすることができます。
サイトのサブドメインからは、クライアントに対して、ドメイン全体に対するクッキーを設定することができます。信頼できるユーザに管理されていないサブドメインから送られたクッキーを許可している場合、この方法で session fixation 攻撃が可能になってしまいます。
For example, an attacker could log into good.example.com
and get a valid
session for their account. If the attacker has control over bad.example.com
,
they can use it to send their session key to you since a subdomain is permitted
to set cookies on *.example.com
. When you visit good.example.com
,
you'll be logged in as the attacker and might inadvertently enter your
sensitive personal data (e.g. credit card info) into the attacker's account.
Another possible attack would be if good.example.com
sets its
SESSION_COOKIE_DOMAIN
to "example.com"
which would cause
session cookies from that site to be sent to bad.example.com
.
JSONSerializer
を使用している場合には json
でシリアライズできるどんな値でも、 PickleSerializer
を使用している場合には pickle
でシリアライズできるどんな Python オブジェクトでも、保存することができます。django_session
という名前のテーブルに保存されます。SessionStore
オブジェクト¶Django が内部でセッションを操作する時は、対応するセッションエンジンの session store オブジェクトを使用します。慣習により、session store オブジェクトは SessionStore
と名付けられていて、SESSION_ENGINE
で指定したモジュール内に置かれています。
Django で利用可能なすべての SessionStore
クラスは、SessionBase
を継承していて、以下のデータを操作するメソッドを実装しています。
exists()
create()
save()
delete()
load()
clear_expired()
独自のセッションエンジンを作ったり、既存のものをカスタマイズするには、SessionBase
か既存の SessionStore
クラスを継承した新しいクラスを作る必要があるでしょう。
You can extend the session engines, but doing so with database-backed session engines generally requires some extra effort (see the next section for details).
Django に含まれるデータベースを使ったセッションエンジン (具体的に言えば、db
と cached_db
) をカスタマイズするには、AbstractBaseSession
とともに SessionStore
クラスを継承する必要があるかもしれません。
AbstractBaseSession
と BaseSessionManager
は、INSTALLED_APPS
に django.contrib.sessions
を追加しなくても、django.contrib.sessions.base_session
からインポートすることができます。
base_session.
AbstractBaseSession
¶ベースとなる抽象的なセッションのモデルです。
session_key
¶プライマリーキーです。フィールド自体は40文字までの文字列を格納できますが、現在の実装では、32文字の文字列 (数字と小文字のASCII文字のランダムな列) を生成します。
session_data
¶エンコード・シリアライズされた、セッションディクショナリーを含む文字列です。
expire_date
¶セッションの有効期限を表す datetime オブジェクトです。
有効期限が切れたセッションをユーザが利用することはできませんが、clearsessions
管理コマンドを実行するまでは、ふつうはデータベースに保存されています。
get_session_store_class
()¶セッションモデルで使用するセッションストアクラスを返します。
get_decoded
()¶デコードしたセッションデータを返します。
デコードは、セッションストアのクラスで実行されます。
BaseSessionManager
のサブクラスを作ることで、モデルマネージャをカスタマイズすることもできます。
base_session.
BaseSessionManager
¶encode
(session_dict)¶与えられたセッションディクショナリを、シリアライズ・エンコードした文字列として返します。
エンコードは、モデルクラスに関連付けられたセッションストアのクラスで実行されます。
save
(session_key, session_dict, expire_date)¶与えられたセッションキーに対するセッションデータを保存します。データが空の場合には、セッションを削除します。
SessionStore
クラスのカスタマイズは、以下に挙げるメソッドやプロパティをオーバーライドすることで行えます。
backends.db.
SessionStore
¶データベースを使ったセッションストアを実装しています。
get_model_class
()¶カスタマイズしたセッションモデルを返す必要がある場合には、このメソッドをオーバーライドします。
create_model_instance
(data)¶現在のセッションの状態を表す、セッションモデルオブジェクトの新しいインスタンスを返します。
このメソッドをオーバーライドすると、セッションモデルのデータをデータベースへ保存する前に修正することができます。
backends.cached_db.
SessionStore
¶キャッシュデータベースを使ったセッションストアを実装しています。
cache_key_prefix
¶キャッシュのキー文字列を作るためにセッションキーに追加するプリフィックスです。
The example below shows a custom database-backed session engine that includes an additional database column to store an account ID (thus providing an option to query the database for all active sessions for an account):
from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.contrib.sessions.base_session import AbstractBaseSession
from django.db import models
class CustomSession(AbstractBaseSession):
account_id = models.IntegerField(null=True, db_index=True)
@classmethod
def get_session_store_class(cls):
return SessionStore
class SessionStore(DBStore):
@classmethod
def get_model_class(cls):
return CustomSession
def create_model_instance(self, data):
obj = super().create_model_instance(data)
try:
account_id = int(data.get('_auth_user_id'))
except (ValueError, TypeError):
account_id = None
obj.account_id = account_id
return obj
If you are migrating from the Django's built-in cached_db
session store to
a custom one based on cached_db
, you should override the cache key prefix
in order to prevent a namespace clash:
class SessionStore(CachedDBStore):
cache_key_prefix = 'mysessions.custom_cached_db_backend'
# ...
The Django sessions framework is entirely, and solely, cookie-based. It does not fall back to putting session IDs in URLs as a last resort, as PHP does. This is an intentional design decision. Not only does that behavior make URLs ugly, it makes your site vulnerable to session-ID theft via the "Referer" header.
2022年6月01日