Наиболее оптимизированный способ удаления всех сеансов для определенного пользователя в Django?

Я использую Django 1.3, используя промежуточное ПО для сеансов и промежуточное ПО для аутентификации:

# settings.py

SESSION_ENGINE = django.contrib.sessions.backends.db   # Persist sessions to DB
SESSION_COOKIE_AGE = 1209600                           # Cookies last 2 weeks

Каждый раз, когда пользователь входит в систему из другого места (другого компьютера / браузера), новый Сеанс ( ) создается и сохраняется с уникальным 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 для этого, или мне придется изменить сеансы для этого? По умолчанию в нем есть только столбцы session_key , session_data и expire_date .

Спасибо за любую информацию или помощь, которую вы можете предложить. :)

17
задан Dave Gallagher 11 July 2011 в 10:18
поделиться