Djangoのセッション管理について
普段django使ってアプリ開発とかしてるわけですが、実は中身がどうなってるのかあまり知らずに使ってます。
今日はなんとなくセッション管理について調べてみました。
セッションを使うには?
セッションを有効にする方法
MIDDLEWARE_CLASSESに、 'django.contrib.sessions.middleware.SessionMiddleware' を入れる
INSTALLED_APPSに 'django.contrib.sessions' を入れる
とはいえ、どちらもデフォルトで入っている。
セッション使わない場合は外したほうがパフォーマンスがよいのでしょう。
セッションエンジン
セッションはデフォルトではdbに保存される
テーブル名はdjango_session
モデルはdjango.contrib.sessions.models.Session
settings.SESSION_ENGINEを設定することによって、memcachedにしたり、ファイルに保存したり、クッキーベースセッションにしたりできる
memcachedのほうがパフォーマンスがよいのでしょう。ただ永続化はされない、と。
例えばログイン状態をどのようにセッションで管理しているか
django-registrationを使ってログイン、ログアウトするだけのdjangoプロジェクトを作ってセッションに何が入るか見てみました。
まずサイトにアクセスすると、Set-Cookieでsessionidが付与されます。
django_sessionテーブルにはこの時点でデータが保存されてます。
mysql> select * from django_session; +----------------------------------+-------------------------------------------------------------------+---------------------+ | session_key | session_data | expire_date | +----------------------------------+-------------------------------------------------------------------+---------------------+ | d9a0e9ccb8a1ae2ceb0306599f2a9602 | OTk0NDljMmQ2MzI4ZjZlNzkwMDY4YzU5MjJhOGU2ZWQxMzllZTZmNzqAAn1xAS4= | 2013-03-23 08:02:37 | +----------------------------------+-------------------------------------------------------------------+---------------------+ 1 row in set (0.00 sec)
session_keyはSet-Cookieでブラウザに渡された値ですね
session_dataには何が入ってるのでしょうか。
Sessionモデルにget_decodedメソッドが用意されてるので、これで中身を見れます。
>>> from django.contrib.sessions.models import Session >>> Session.objects.get(session_key='d9a0e9ccb8a1ae2ceb0306599f2a9602').get_decoded() {}
空の辞書でした。
ログインページに飛んでみると、その時点でsesseion_dataが書きかわりました。
mysql> select * from django_session; +----------------------------------+----------------------------------------------------------------------------------------------------+---------------------+ | session_key | session_data | expire_date | +----------------------------------+----------------------------------------------------------------------------------------------------+---------------------+ | d9a0e9ccb8a1ae2ceb0306599f2a9602 | ZTg1MjgwZjEwYjYwNTI1M2MxNWNmNDNlMjYyMDQ5MzJmYWMxZjBkYzqAAn1xAVUKdGVzdGNvb2tp ZXECVQZ3b3JrZWRxA3Mu | 2013-03-23 08:08:11 | +----------------------------------+----------------------------------------------------------------------------------------------------+---------------------+
>>> Session.objects.get(session_key='d9a0e9ccb8a1ae2ceb0306599f2a9602').get_decoded() {'testcookie': 'worked'}
testcookieというのがセットされてました。djangoのdjango.contrib.auth.views.login関数がセットしたんですね。
ログインしてみます
302レスポンスが返されて、Set-Cookieがついてるのでsession_keyが変わりました。
mysql> select * from django_session; +----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | session_key | session_data | expire_date | +----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+ | c88514f077edd10eecbbfdc822657f9c | YWY1MDVlZDAyYmQ2MGRkNGQyZGQ4YjhkNDZiNzBkYjc2YzJlM2Y0YjqAAn1xAShVEl9hdXRoX3Vz ZXJfYmFja2VuZHECVSlkamFuZ28uY29udHJpYi5hdXRoLmJhY2tlbmRzLk1vZGVsQmFja2VuZHED VQ1fYXV0aF91c2VyX2lkcQSKAQF1Lg== | 2013-03-23 08:14:38 | +----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+
ログイン後の状態
>>> Session.objects.get(session_key='c88514f077edd10eecbbfdc822657f9c').get_decoded() {'_auth_user_id': 1L, '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend'}
ユーザーIDとbackendを保持してますね
これでcookieでsession_keyが渡されれば、どのユーザーからのアクセスかわかる、すなわちログイン状態ってわけですね
ログアウトしてみます。
ログアウト後のリダイレクト先でまたSet-Cookieでsessionidが変わります
mysql> select * from django_session; +----------------------------------+-------------------------------------------------------------------+---------------------+ | session_key | session_data | expire_date | +----------------------------------+-------------------------------------------------------------------+---------------------+ | c5e527f0f14901ab8ed0a35d3943729f | OTk0NDljMmQ2MzI4ZjZlNzkwMDY4YzU5MjJhOGU2ZWQxMzllZTZmNzqAAn1xAS4= | 2013-03-23 08:21:40 | +----------------------------------+-------------------------------------------------------------------+---------------------+ 1 row in set (0.00 sec)
session_dataはまた空になりました
>>> from django.contrib.sessions.models import Session >>> Session.objects.get(session_key='c5e527f0f14901ab8ed0a35d3943729f').get_decoded() {}
ログイン状態のときセッションにセットされた値はどこで使ってるのか、みてみると
AuthenticationMiddlewareでrequest.userをセットしてるので、その辺で使ってそうです。
class AuthenticationMiddleware(object): def process_request(self, request): assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'." request.user = SimpleLazyObject(lambda: get_user(request))
get_userを追っかけてみると
django.contrib.auth.get_userで使ってました。
SESSION_KEYが'_auth_user_id'、BACKEND_SESSION_KEYが'_auth_user_backend'ですね
def get_user(request): from django.contrib.auth.models import AnonymousUser try: user_id = request.session[SESSION_KEY] backend_path = request.session[BACKEND_SESSION_KEY] backend = load_backend(backend_path) user = backend.get_user(user_id) or AnonymousUser() except KeyError: user = AnonymousUser() return user
backendにはModelBackend以外になにがあるのでしょうか
調べてみるとRemoteUserBackendというのがありました。
これは今度調べてみよう。