本文介绍: 通过记录令牌生成时间戳,我们可以通过定期清理方式清理掉一定时间前生成(过老)的令牌,从而实现令牌的时限性,在一定程度上也减少了。记录令牌生成时间能让我们更便捷的根据时间戳对令牌进行排序然后再对一定时间前生成(过老)的令牌进行删除。秒),在每次清理令牌数据时,我们找到令牌生成时间一个星期前的数据,并将这些令牌和令牌生成时间数据全部删除。随着登录用户的增多,令牌存储所需的内存也会不断增加,这时,我们需要定期清理过期的令牌数据。,记录了用户令牌则应该也有对应的令牌生成时间,所以我们应该使用
相关知识

大多数网站都会使用 cookie 记录用户的身份cookie 是由少量数据组成的字符串(通常还要经过加密)。网站会要求浏览器存储这些数据,并在向服务端发起请求时将这些数据传回给服务端

通常,用于处理登录识别用户身份)的 cookie 分为两种:

这两种 cookie 各有优缺,我们可以通过一个表格对比两者的优缺:

类型 优点 缺点
签名式 cookie 直接存储用户信息,方便验证用户身份;可以包含额外信息;对 cookie 进行签名简单 遗漏签名会导致安全漏洞加密方法不当会泄露用户敏感信息
令牌式 cookie cookie 体积小,可加快通信速度 需要使用数据库存储令牌,会造成额外开销

为了避免安全漏洞,本关卡中,我们使用令牌式 cookie

篇文章将教会你掌握1如何核对令牌,2如何更新令牌,3如何定期清理无用信息

如何核对令牌

前面提到了令牌式 cookie最大缺点就是会造成额外开销。大多数关系数据库每台数据库服务器上只能插入、更新或删除 200 - 2000 个数据行/秒。当网站负载变高时,数据库成为了瓶颈。所以,我们需要使用 Redis 取代关系数据库存放令牌。

首先,我们约定令牌的存储方式。我们使用一个哈希存储登录令牌与用户的映射关系,其中:

所以核对令牌就变得十分简单方法如下

import redis

conn = redis.Redis()

def check_token(token):
return conn.hget('login', token)

我们使用 hget() 方法Redis 中取出并返回令牌对应的用户 ID,而**当令牌不存在时,该方法则返回 None**,从而达到核对检查效果

如何更新令牌

更新令牌需要两个工作

  • 记录用户令牌
  • 记录令牌生成时间

由于令牌存在被人窃取的可能,所以我们不允许令牌永不过期通过记录令牌生成的时间戳,我们可以通过定期清理的方式,清理掉一定时间前生成(过老)的令牌,从而实现令牌的时限性,在一定程度上也减少了 Redis 的存储量,避免内存过高消耗。

使用有序集合记录令牌生成时间能让我们更便捷的根据时间戳对令牌进行排序然后再对一定时间前生成(过老)的令牌进行删除。将时间戳作为分值,令牌作为成员,记录到有序集合 recent:token 中:

import time

timestamp = time.time() #返回当前时间的时间戳(1970年后经过的浮点秒数)
conn.zadd('recent:token', token, timestamp)

而记录用户令牌可以使用 hset() 方法,将 tokenuser_id 的域-值对关系记录到哈希中:

conn.hset('login', token, user_id)

上述两个操作相关,记录了用户令牌则应该也有对应的令牌生成时间,所以我们应该使用事务将两条命令包起来,最后一起提交Redis 处理

def update_token(token, user_id):
timestamp = time.time()
pipe = conn.pipeline()
pipe.hset('login', token, user_id)
pipe.zadd('recent:token', token, timestamp)
pipe.execute()
如何定期清理无用信息

随着登录用户的增多,令牌存储所需的内存也会不断增加,这时,我们需要定期清理过期的令牌数据。

决定令牌的有效时间需要权衡数据安全与用户体验两方面:

综合上述两个方面的考虑,我们将令牌的有效时间设置一个星期(86400秒),在每次清理令牌数据时,我们找到令牌生成时间在一个星期前的数据,并将这些令牌和令牌生成时间数据全部删除。

寻找一个星期前生成的令牌是关键,我们可以使用当前 Unix 时间减去 86400 得到一个星期前的 Unix 时间戳,然后使用有序集合命令 ZRANGEBYSCORE 获取有序集合 recent:token 中所有分值(生成时间)大于等于 0,小于等于一个星期前的 Unix 时间戳的成员

one_week_ago_timestamp = time.time() - 86400

exipred_tokens = conn.zrangebyscore('recent:token', 0, one_week_ago_timestamp)

接下来,我们要从有序集合 recent:token 中删除掉 expired_tokens 的所有成员,以及从哈希 login移除所有过期token 域。

为了减少客户端Redis 之间通信次数,我们可以直接使用 ZREMRANGEBYSCORE 命令移除有序集合 recent:token 中所有分值(生成时间)大于等于 0,小于等于一个星期前的 Unix 时间戳的成员

conn.zremrangebyscore('recent:token', 0, one_week_ago_timestamp)
conn.hdel('login', *expired_tokens)

我们使用了 hdel() 方法一次性从哈希 login移除了所有过期token 域,由于 expired_tokens 是一个数组,而客户端默认输入的值转换为字符串,所以我们在这里要使用 *expired_tokens,以指针的形式调用 expired_tokens 变量传入多个参数(域)

让清理方法自动执行

你可以使用守护进程的方式来保证这个方法始终在运行,也可以通过定时任务cron job每隔一段时间执行一次

因为这些知识超出了本实训讲解范围,在这里就不再详述。

编程要求

根据提示,在右侧Begin-End区域补充代码完成令牌管理的后端处理逻辑

原文地址:https://blog.csdn.net/nuhao/article/details/134702941

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_42054.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注