【Redis实战】快速简单搭建聊天室03——实现登陆功能

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【Redis实战】快速简单搭建聊天室03——实现登陆功能

登录过程的逻辑原理如下:


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()

其中,主要说明如下:

  • 第2-4行:初始化一些固定到字符串,这些字符串将要作为Redis到Key使用
  • 第7行:连接本地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

主要说明如下:

  • 第12行:调用集合sadd命令把昵称添加到Key为self.chat_room_nick_set这个属性值的集合中。
  • 第13-15行:判断Redis返回的数字,如果返回数字为1,表示原来集合没有这个昵称,此时这个方法需要返回False。如果返回的数字不是1,那么说明原来已经有这个昵称了,这个方法就要返回True。

修改is_nick_already_exists方法

修改完成以后,重启网站,再次尝试登录。可以发现验证昵称是否重复的功能已经正常。不会再出现输入任何昵称都提示昵称已经存在的问题了。

但问题是,即使输入一个全新的昵称,网站也不会进入聊天室页面,而是闪一下以后继续留在登录页面。


03

实现设置和获取Token的功能

所谓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)

其中,主要说明如下:

  • 第11行:拼接出完整的字符串Key
  • 第12行:在Redis中设置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()

其中,主要说明如下:

  • 第12行:拼出这个昵称对应的字符串Key
  • 第13行:从Redis中读取这个Key的值
  • 第14行:如果这个Key不存在,就返回None;如果Key存在,就把Key对应的bytes型的数据解码为字符串后返回

修改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密码是我们自己生成的。

目录
相关文章
|
11天前
|
存储 NoSQL 前端开发
Redis专题-实战篇一-基于Session和Redis实现登录业务
本项目基于SpringBoot实现黑马点评系统,涵盖Session与Redis两种登录方案。通过验证码登录、用户信息存储、拦截器校验等流程,解决集群环境下Session不共享问题,采用Redis替代Session实现数据共享与自动续期,提升系统可扩展性与安全性。
86 3
Redis专题-实战篇一-基于Session和Redis实现登录业务
|
11天前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
75 1
Redis专题-实战篇二-商户查询缓存
|
6月前
|
数据采集 存储 数据可视化
分布式爬虫框架Scrapy-Redis实战指南
本文介绍如何使用Scrapy-Redis构建分布式爬虫系统,采集携程平台上热门城市的酒店价格与评价信息。通过代理IP、Cookie和User-Agent设置规避反爬策略,实现高效数据抓取。结合价格动态趋势分析,助力酒店业优化市场策略、提升服务质量。技术架构涵盖Scrapy-Redis核心调度、代理中间件及数据解析存储,提供完整的技术路线图与代码示例。
604 0
分布式爬虫框架Scrapy-Redis实战指南
|
3月前
|
缓存 监控 NoSQL
Redis 实操要点:Java 最新技术栈的实战解析
本文介绍了基于Spring Boot 3、Redis 7和Lettuce客户端的Redis高级应用实践。内容包括:1)现代Java项目集成Redis的配置方法;2)使用Redisson实现分布式可重入锁与公平锁;3)缓存模式解决方案,包括布隆过滤器防穿透和随机过期时间防雪崩;4)Redis数据结构的高级应用,如HyperLogLog统计UV和GeoHash处理地理位置。文章提供了详细的代码示例,涵盖Redis在分布式系统中的核心应用场景,特别适合需要处理高并发、分布式锁等问题的开发场景。
274 41
|
1月前
|
存储 NoSQL Redis
采用Redis的Bitmaps实现类似Github连续提交状态的功能。
在现实世界的应用开发中,实现类似于Github提交跟踪系统时,还可能需要考虑用户时区、闰年等日期相关的边界条件,以及辅助数据的存储和查询优化,例如对活跃用户的即时查询和统计等。不过这些都可以在Bitmaps的基础功能之上通过额外的代码逻辑来实现。
69 0
|
3月前
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
1028 7
|
3月前
|
机器学习/深度学习 存储 NoSQL
基于 Flink + Redis 的实时特征工程实战:电商场景动态分桶计数实现
本文介绍了基于 Flink 与 Redis 构建的电商场景下实时特征工程解决方案,重点实现动态分桶计数等复杂特征计算。通过流处理引擎 Flink 实时加工用户行为数据,结合 Redis 高性能存储,满足推荐系统毫秒级特征更新需求。技术架构涵盖状态管理、窗口计算、Redis 数据模型设计及特征服务集成,有效提升模型预测效果与系统吞吐能力。
341 2
|
4月前
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
185 32
|
4月前
|
存储 监控 NoSQL
使用Redis实现延迟消息发送功能
使用 Redis 的密码认证功能,为实例设置密码以防止未授权访问。为消息提供适当加密,确保消息内容在网络传输过程中不被窃取或篡改。
189 16
|
NoSQL API Redis
redis的其他功能
瑞士军刀Redis image.png 慢查询 image.png image.png image.png image.
1111 0