Persisting session variables across login
Upon login, Django calls session.flush()
or session.cycle_key()
, which makes sure nothing from the old session is kept. This is a security measure that protects you against session fixation vulnerabilities. So, when applying this solution, be aware what find of variables you want to persist.
If you want to keep some state, you'll have to restore that after the login was issued.
The solution by Chase Seibert was a great start, it was very insecure due to threadsafety issues in that code. You can find an improved version here, which is safe to use:
from functools import wraps
class persist_session_vars(object):
"""
Some views, such as login and logout, will reset all session state.
(via a call to ``request.session.cycle_key()`` or ``session.flush()``).
That is a security measure to mitigate session fixation vulnerabilities.
By applying this decorator, some values are retained.
Be very aware what find of variables you want to persist.
"""
def __init__(self, vars):
self.vars = vars
def __call__(self, view_func):
@wraps(view_func)
def inner(request, *args, **kwargs):
# Backup first
session_backup = {}
for var in self.vars:
try:
session_backup[var] = request.session[var]
except KeyError:
pass
# Call the original view
response = view_func(request, *args, **kwargs)
# Restore variables in the new session
for var, value in session_backup.items():
request.session[var] = value
return response
return inner
and now you can write:
from django.contrib.auth import views
@persist_session_vars(['some_field'])
def login(request, *args, **kwargs):
return views.login(request, *args, **kwargs)
And for class based views (django-allauth):
import allauth.account.views as auth_views
from django.utils.decorators import method_decorator
@method_decorator(persist_session_vars(['some_field']), name='dispatch')
class LoginView(auth_views.LoginView):
pass
and use that view in the url patterns:
import allauth.urls
from django.conf.urls import include, url
from . import views
urlpatterns = [
# Views that overlap the default:
url(r'^login/$', views.LoginView.as_view(), name='account_login'),
# default allauth urls
url(r'', include(allauth.urls)),
]
When you login/logout Django will flush all sessions if another user logs in (request.session.flush() in auth/init.py).
You're better of storing user settings in the database and add some middleware to get that data and store it in your request.