我正在运行 Django 1.3,使用 Sessions 中间件和 Auth 中间件:
# 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, Session.objects.filter(expire_date__gte=datetime.datetime.now())
, 解码它们,并检查它是否与用户匹配。如果数据库中存储了100,000个以上的session,那么这将对数据库非常昂贵。有没有更适合数据库的方法?是否有Sessions / Auth中间件设置可以让您将用户名存储为Sessions表中的列,以便我可以对其运行SQL,或者我必须修改Sessions才能实现这一点?默认情况下,它只具有
session_key
,session_data
和expire_date
列。感谢您能提供的任何见解或帮助。 :)
user.pk
转换为字符串才能使其正常工作:if str(user.pk) == session_data.get('_auth_user_id')
。 - Ben Konrath