Я запускаю Django 1.3, используя Session Middleware и Auth Middleware:
# settings.py
SESSION_ENGINE = django.contrib.sessions.backends.db # Persist sessions to DB
SESSION_COOKIE_AGE = 1209600 # Cookies last 2 weeks
Каждый раз, когда пользователь регистрируется в другом месте (другой компьютер/браузер), создается новый Session()
и сохраняется с уникальным session_id
. Это может привести к появлению нескольких записей базы данных для одного и того же пользователя. Их логин сохраняется на этом node до тех пор, пока файл cookie не будет удален или сеанс не завершится.
Когда пользователь меняет свой пароль, я хочу удалить все оставшиеся сеансы для этого пользователя из БД. Таким образом, после смены пароля они вынуждены повторно войти в систему. Это касается безопасности, например, если ваш компьютер украден, или вы случайно оставили свой вход в открытый терминал.
Я хочу знать лучший способ оптимизировать это. Вот как я это сделал:
# sessions_helpers.py
from django.contrib.sessions.models import Session
import datetime
def all_unexpired_sessions_for_user(user):
user_sessions = []
all_sessions = Session.objects.filter(expire_date__gte=datetime.datetime.now())
for session in all_sessions:
session_data = session.get_decoded()
if user.pk == session_data.get('_auth_user_id'):
user_sessions.append(session)
return user_sessions
def delete_all_unexpired_sessions_for_user(user, session_to_omit=None):
for session in all_unexpired_sessions_for_user(user):
if session is not session_to_omit:
session.delete()
Очень упрощенный вид:
# views.py
from django.http import HttpResponse
from django.shortcuts import render_to_response
from myapp.forms import ChangePasswordForm
from sessions_helpers import delete_all_unexpired_sessions_for_user
@never_cache
@login_required
def change_password(request):
user = request.user
if request.method == 'POST':
form = ChangePasswordForm(data=request)
if form.is_valid():
user.set_password(form.get('password'))
user.save()
request.session.cycle_key() # Flushes and replaces old key. Prevents replay attacks.
delete_all_unexpired_sessions_for_user(user=user, session_to_omit=request.session)
return HttpResponse('Success!')
else:
form = ChangePasswordForm()
return render_to_response('change_password.html', {'form':form}, context_instance=RequestContext(request))
Как вы можете видеть в sessions_helpers.py
, я должен вытащить каждый оставшийся сеанс из БД, Session.objects.filter(expire_date__gte=datetime.datetime.now())
, декодировать все из них, а затем проверить, совпадает ли он с пользователем или нет. Это будет чрезвычайно дорогостоящим для базы данных, если, например, там хранится 100 000 + сеансов.
Есть ли способ для более удобного использования базы данных? Есть ли параметр Session/Auth Middleware, который позволит вам сохранить имя пользователя в качестве столбца в таблице "Сессии", чтобы я мог запускать SQL против этого или мне нужно будет изменить сеансы для этого? Из-за коробки он имеет столбцы session_key
, session_data
и expire_date
.
Спасибо за любое понимание или помощь, которую вы можете предложить.:)