实现登录功能
登录过程的逻辑原理如下:
1
用户输入昵称并单击登录按钮
2
网站在Redis集合中检查昵称是否存在
3
如果昵称存在,提示用户昵称存在,不能登录
4
如果昵称不存在,把昵称添加到集合中,防止其他人再使用这个昵称
5
基于昵称与当前时间戳生成Token
6
把昵称与Token保存到Redis中,方便再次查询
7
把昵称与Token设置到浏览器Cookies中,实现今后进入聊天界面免去登录过程
01
创建Redis连接实例
要使用Redis,首先需要创建Redis到连接实例。连接实例创建在__init__()方法中,以方便在整个RedisUtil类中进行调用。
修改RedisUtil类的__init__()方法,连接本地到Redis:
03 def __init__(self):
04 self.chat_room_nick_set = 'chat_room_nick_set'
05 self.cookie_nick = 'cookie-{}'
06 self.chat_list = 'chat_list'
07
08 # 你需要在这里初始化Redis
09 self.client = redis.Redis()
其中,主要说明如下:
连接本地Redis
02
要检查昵称是否重复,用到的是Redis到集合。如果向集合中添加一条内容,集合返回1,表示这条内容原来不在集合中;如果返回0,表示集合里面已经有这条内容了。
根据is_nick_already_exists()方法注释到提示,完善这个方法:
01 def is_nick_already_exists(self, nick):
02 """
03 你需要实现这个方法
04
05 判断这个昵称是不是已经登录过了。如果已经登录,那么就不能使用这个昵称。
06 使用Redis的集合实现,如果把昵称sadd到集合中返回1,说明这个昵称之前
07 不存在,此时应该返回False,如果返回0,表示这个昵称之前已经存在了,此时应该返回True。
08
09 :param nick: 昵称
10 :return: True or False
11 """
12 is_flag = self.client.sadd(self.chat_room_nick_set, nick)
13 if is_flag == 1:
14 return False
15 return True
主要说明如下:
修改is_nick_already_exists方法
修改完成以后,重启网站,再次尝试登录。可以发现验证昵称是否重复的功能已经正常。不会再出现输入任何昵称都提示昵称已经存在的问题了。
但问题是,即使输入一个全新的昵称,网站也不会进入聊天室页面,而是闪一下以后继续留在登录页面。
03
所谓Token,本质上就是一段用来验证身份的字符串。在本项目中,Token是昵称加上当前时间戳并转换为MD5以后的值。
设置与获取Token对应的方法是set_token()方法和get_token()方法。这两个方法本质上就是在Redis添加字符串和读取字符串。
保存Token的字符串,Key为“cookie-昵称”
例如:
“cookie-王小一”,字符串的值为Token,每一个昵称对应一个字符串。
set_token()方法修改后的代码如下:
01 def set_token(self, nick, token):
02 """
03 你需要实现这个方法
04
05 设定Token,这样的好处是只需要登录一次,以后可以直接访问/room页面直接进入聊天窗口
06 使用Redis的字符串实现,字符串的Key是"cookie-昵称",例如"cookie-青南",值为参数token
07 :param nick: 昵称
08 :param token: md5字符串
09 :return: None
10 """
11 key = self.cookie_nick.format(nick)
12 self.client.set(key, token)
其中,主要说明如下:
get_token方法修改后的代码如下:
01 def get_token(self, nick):
02 """
03 你需要实现这个方法
04
05 获取Token,从"cookie-昵称"token并返回。
06
07 使用Redis的字符串实现,字符串的Key为"cookie-昵称",例如"cookie-青南",如果这个Key存在,
08 就获取它的值并返回,如果这个Key不存在,就返回None
09 :param nick: 昵称
10 :return: None 或者 Token字符串
11 """
12 key = self.cookie_nick.format(nick)
13 token = self.client.get(key)
14 return None if not token else token.decode()
其中,主要说明如下:
修改set_token()方法和get_token()方法
修改完成以后,重启网站,再次尝试使用新的名字登录,发现已经可以正常进入聊天室页面了。
成功登录聊天室页面
但是聊天窗口始终没有任何信息显示,发送信息也没有效果。
04
小知识:为什么需要Token?
网页基于HTTP协议,而HTTP协议是没有状态的。什么叫做没有状态?就是在你访问了两个页面,但是网站并不知道这两次访问来自同一个人。你访问登录页面是一次请求,访问聊天室页面是另一个请求,网站怎么知道访问聊天室的这个人就是刚刚登录的那个人?
为了让这种没有状态变得有状态,就引入了一个叫做Cookies的东西。Cookies本质上是一小段文本信息,浏览器发送每一个请求都带上这段文本信息,于是网站看到两次请求都有相同的Cookies,就知道这两次请求来自同一个人。
例如:
一个用户用昵称“青南”进行登录,网站收到这个登录请求以后,就给这个浏览器返回一段Cookies:“这个人是青南”。然后浏览器每次访问这个网站的其他页面都会带上这一段话。当这个用户访问聊天室页面的时候,网站先检查Cookies,发现Cookies中有“这个人是青南”,所以网站就知道这个用户之前是登录过的,直接让他浏览聊天室页面。
如果现在来了一个坏人,他先用“坏人”这个昵称登录网站,网站本来返回给他的Cookies是:“这个人是坏人”。但是这个坏人强行把浏览器的Cookies修改了,改成了“这个人是青南”。于是他就可以用青南的身份招摇撞骗。这叫做“Cookies欺骗”。
为了防止Cookies欺骗,网站在用户第一次请求的时候,会根据用户昵称和当前时间戳生成一个密码,网站先把这个密码保存到自己身边,然后再设置到这个用户的浏览器Cookies中。
这样一来,昵称和密码必需一一对应才能正常访问网站。当用户再次访问聊天室页面的时候,网站会从Cookies中读出昵称和这个密码,然后与自己保存的密码进行对比,发现匹配才让这个用户正常访问聊天室页面。这就是防止Cookies欺骗最简单的办法。因为修改昵称很容易,但是知道这个密码就很难。
这个密码就是Token。
Token与我们平时的银行卡密码,QQ密码不同的地方在于,Token是网站生成并返回给我们的,我们只需要记住就可以了。而银行卡密码和QQ密码是我们自己生成的。