来龙去脉

每个网站的用户在登录之后都会有重置密码的功能,如果有两个用户同时登录到一个账号,并且用户A在登录后重置了密码,而用户B却没有退出登陆的情况下,用户B就可以在继续操做账号,所以我们就要在A执行操作后,让B不能够访问账号,那么如何解决这个问题呢?

Session

HTTP协议是无状态的,服务器判断一个用户是否为登录状态的方法就是通过判断客户端请求的cookie中的sessionid,如果sessionid和服务器端保存的session中的id相同,那么这个客户端就可以被认为是合法的用户。(注意:服务器端保存的某个账号的session有很多个,session中的许多信息是相同的,比如user_id,username等,但是sessionid确实不同的。)

那么我们的解决方法就可以分为以下几步:

  1. 某个用户重置密码
  2. 立即将数据库中session表进行过滤,删除userid为这个重置用户的id的所有session
  3. 根据请求信息,重写生成session,响应返回

Django中处理session的坑

Django中session model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Session(AbstractBaseSession):
objects = SessionManager()
@classmethod
def get_session_store_class(cls):
from django.contrib.sessions.backends.db import SessionStore
return SessionStore
class Meta(AbstractBaseSession.Meta):
db_table = 'django_session'
class BaseSessionManager(models.Manager):
def encode(self, session_dict):
"""
Return the given session dictionary serialized and encoded as a string.
"""
session_store_class = self.model.get_session_store_class()
return session_store_class().encode(session_dict)
def save(self, session_key, session_dict, expire_date):
s = self.model(session_key, self.encode(session_dict), expire_date)
if session_dict:
s.save()
else:
s.delete() # Clear sessions with no data.
return s
class AbstractBaseSession(models.Model):
session_key = models.CharField(_('session key'), max_length=40, primary_key=True)
session_data = models.TextField(_('session data'))
expire_date = models.DateTimeField(_('expire date'), db_index=True)
objects = BaseSessionManager()
class Meta:
abstract = True
verbose_name = _('session')
verbose_name_plural = _('sessions')
def __str__(self):
return self.session_key
@classmethod
def get_session_store_class(cls):
raise NotImplementedError
def get_decoded(self):
session_store_class = self.get_session_store_class()
return session_store_class().decode(self.session_data)

从session的模型中我们可以看出,session_data是通过编码后保存的,session_data中就包含请求的user_id,当我们要删除所有请求user的session的时候就需要根据这个user_id来查找,即session模型不支持反向查询,所以我们在处理这的时候需要查询出所有session,然后对每个session执行get_decoded方法来查找判断user_id。这个放下效率肯定会很低下,不过暂时也没有想到更好的方法。。