Я использую Django 1.3, использую промежуточное ПО Sessions и промежуточное ПО аутентификации:
# settings.py
SESSION_ENGINE = django.contrib.sessions.backends.db # Persist sessions to DB
SESSION_COOKIE_AGE = 1209600 # Cookies last 2 weeks
Каждый раз, когда пользователь входит в систему из другого места (с другого компьютера / браузера), создается новый Session()
, который сохраняется с уникальным session_id
. Это может привести к нескольким записям базы данных для одного и того же пользователя. Их логин сохраняется на этом узле до тех пор, пока 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 сеансов.
Есть ли более удобный для базы данных способ сделать это? Есть ли параметр Sessions / Auth Middleware, который позволит вам сохранить имя пользователя в виде столбца в таблице Sessions, чтобы я мог запускать SQL для этого, или мне придется изменить Sessions для этого? Из коробки есть только столбцы session_key
, session_data
и expire_date
.
Спасибо за понимание или помощь, которую вы можете предложить. :)