使用Flask开发简单接口(4)--借助Redis实现token验证
前言
在之前我们已开发了几个接口,并且可以正常使用,那么今天我们将继续完善一下。我们注意到之前的接口,都是不需要进行任何验证就可以使用的,其实我们可以使用 token ,比如设置在修改或删除用户信息的时候需要进行 token 登录验证,这个地方我们将引入 Redis 用于存储登录时产生的 token 。
本人环境:Python 3.7.0 、Redis 5.0.8
新增Redis配置
我们在项目根路径下 config 包中,修改文件 setting.py ,在该文件中配置 Redis 的服务器地址、端口、密码、token过期时间(单位:秒)等参数。
# Redis配置
REDIS_HOST = "192.168.89.128"
REDIS_PORT = 6379
REDIS_PASSWD = "123456"
# token过期时间(单位:秒)
EXPIRE_TIME = 600
Python操作Redis
- 安装redis模块
使用Python来操作Redis,需要用到 redis 这个第三方库,具体安装方法如下:
pip install redis
我这里安装的版本是 3.4.1。
D:\>pip3 show redis
Name: redis
Version: 3.4.1
Summary: Python client for Redis key-value store
Home-page: https://github.com/andymccurdy/redis-py
Author: Andy McCurdy
Author-email: sedrik@gmail.com
License: MIT
Location: d:\python\installation\lib\site-packages
Requires:
Required-by:
- 封装Python操作Redis的代码
我们在项目根路径下 common 包中,新建文件 redis_operate.py ,该文件下简单封装了Python操作Redis的代码,后续将通过调用该文件的 redis_db 对象及方法来操作Redis。
import redis
from config.setting import REDIS_HOST, REDIS_PORT, REDIS_PASSWD, EXPIRE_TIME
class RedisDb():
def __init__(self, host, port, passwd):
# 建立数据库连接
self.r = redis.Redis(
host=host,
port=port,
password=passwd,
decode_responses=True # get() 得到字符串类型的数据
)
def handle_redis_token(self, key, value=None):
if value: # 如果value非空,那么就设置key和value,EXPIRE_TIME为过期时间
self.r.set(key, value, ex=EXPIRE_TIME)
else: # 如果value为空,那么直接通过key从redis中取值
redis_token = self.r.get(key)
return redis_token
redis_db = RedisDb(REDIS_HOST, REDIS_PORT, REDIS_PASSWD)
在Redis中,我们存储数据是 str 字符串类型,但由于python3与redis交互的驱动问题,默认通过 get() 取出来是 bytes 字节类型,为解决这个问题,我们在上面代码创建连接时,设置了 decode_responses=True ,这样通过 get() 取出来就是 str 字符串类型。
登录时设置token
一般情况,我们登录成功之后,才会产生token,以便在请求其他接口时进行登录验证。因此,我们需要在返回登录成功信息之前,设置token,并把当前登录用户和设置token,作为redis中的 key 和 value ,放到redis中进行存储。修改用户登录接口如下:
@app.route("/login", methods=['POST'])
def user_login():
"""登录用户"""
username = request.values.get("username", "").strip()
password = request.values.get("password", "").strip()
if username and password: # 注意if条件中空串 "" 也是空, 按False处理
sql1 = "SELECT username FROM user WHERE username = '{}'".format(username)
res1 = db.select_db(sql1)
print("查询到用户名 ==>> {}".format(res1))
if not res1:
return jsonify({"code": 1003, "msg": "用户名不存在!!!"})
sql2 = "SELECT * FROM user WHERE username = '{}' and password = '{}'".format(username, password)
res2 = db.select_db(sql2)
print("获取 {} 用户信息 == >> {}".format(username, res2))
if res2:
timeStamp = int(time.time()) # 获取当前时间戳
token = "{}{}".format(username, timeStamp)
redis_db.handle_redis_token(username, token) # 把token放到redis中存储
login_info = { # 构造一个字典,将 id/username/token/login_time 返回
"id": res2[0]["id"],
"username": username,
"token": token,
"login_time": time.strftime("%Y/%m/%d %H:%M:%S")
}
return jsonify({"code": 0, "login_info": login_info, "msg": "恭喜,登录成功!"})
return jsonify({"code": 1002, "msg": "用户名或密码错误!!!"})
else:
return jsonify({"code": 1001, "msg": "用户名或密码不能为空!!!"})
在这里,我们设置的 token 是由 用户名+当前时间戳 拼接而成的,并把其放到redis中,可以到redis中查看token,或者在登录成功后接口返回数据中的 login_info 中查看。而 token 的有效时间,这个是在配置文件 setting.py 中设置的 EXPIRE_TIME = 600 ,即 600 秒 后当前用户的 token 才会过期失效。
删除用户请求接口实现
接下来,我们准备新开发个接口:删除用户接口。该接口需要 管理员用户 登录认证后才可以进行操作,管理员用户可以删除任何 普通用户 信息。
原本我是想通过 DELETE 请求方式来开发该接口,但好像使用 DELETE 方式的HTTP请求中,不允许传入Body,因此为了方便一些,我们这里仍使用 POST 方式来请求。
- 删除用户接口(POST请求方式)
@app.route("/delete/user/<int:id>", methods=['POST'])
def user_delete(id):
username = request.json.get("username", "").strip() # 当前登录的管理员用户
token = request.json.get("token", "").strip() # token口令
if username and token:
redis_token = redis_db.handle_redis_token(username) # 从redis中取token
if redis_token:
if redis_token == token: # 如果从redis中取到的token不为空,且等于请求body中的token
sql1 = "SELECT role FROM user WHERE username = '{}'".format(username)
res1 = db.select_db(sql1)
print("根据用户名 【 {} 】 查询到用户类型 == >> {}".format(username, res1))
user_role = res1[0]["role"]
if user_role == 0: # 如果当前登录用户是管理员用户
sql2 = "SELECT * FROM user WHERE id = '{}'".format(id)
res2 = db.select_db(sql2)
print("根据用户ID 【 {} 】 查询到用户信息 ==>> {}".format(id, res2))
if not res2: # 如果要删除的用户不存在于数据库中,res2为空
return jsonify({"code": 3005, "msg": "删除的用户ID不存在,无法进行删除,请检查!!!"})
elif res2[0]["role"] == 0: # 如果要删除的用户是管理员用户,则不允许删除
return jsonify({"code": 3006, "msg": "用户ID:【 {} 】,该用户不允许删除!!!".format(id)})
else:
sql3 = "DELETE FROM user WHERE id = {}".format(id)
db.execute_db(sql3)
print("删除用户信息SQL ==>> {}".format(sql3))
return jsonify({"code": 0, "msg": "恭喜,删除用户信息成功!"})
else:
return jsonify({"code": 3004, "msg": "当前用户不是管理员用户,无法进行操作,请检查!!!"})
else:
return jsonify({"code": 3003, "msg": "token口令不正确,请检查!!!"})
else:
return jsonify({"code": 3002, "msg": "当前用户未登录,请检查!!!"})
else:
return jsonify({"code": 3001, "msg": "管理员用户/token口令不能为空,请检查!!!"})
相关的接口返回码和请求场景如下:
| 接口返回码 | 请求场景 |
|---|---|
| 0 | 请求参数正确,删除用户成功! |
| 3001 | 请求参数中,管理员用户/token口令,任一参数为空 |
| 3002 | 请求参数中,当前操作用户没有token,登录验证失败 |
| 3003 | 请求参数中的token值,与redis中的token值不一致 |
| 3004 | 请求参数中,当前操作用户不是管理员用户,无权限进行操作 |
| 3005 | 请求参数中,要删除的用户ID不存在 |
| 3006 | 请求参数中,要删除的用户是管理员用户,不允许删除 |
可参考如下进行接口请求:
请求方式:POST
请求地址:http://127.0.0.1:5000/delete/user/5
请求头:
Content-Type: application/json
Body:{"username": "wintest", "token": "wintest1587830406"}

OK,通过以上操作,我们已成功借助Redis来实现token登录验证,当然,我们redis的作用还有很多,在这里我们只是简单的应用了一些,要学习的东西还是很多。相关代码已上传到GitHub,大家有兴趣的可以基于此进行学习及开展接口测试。
GitHub源码地址:https://github.com/wintests/flaskDemo
使用Flask开发简单接口(4)--借助Redis实现token验证的更多相关文章
- 使用Flask开发简单接口(2)--POST请求接口
今天我们继续学习如何使用Flask开发POST接口:用户注册接口和用户登录接口. request接收参数 当我们在页面发出一个POST请求,请求传到服务器时,需要如何拿到当前请求的数据呢?在Flask ...
- 使用Flask开发简单接口(1)--GET请求接口
前言 很多想学习接口测试的同学,可能在最开始的时候,常常会因没有可以练习的项目而苦恼,毕竟网上可以练习的接口项目不多,有些可能太简单了,有些可能又太复杂了,或者是网上一些免费接口请求次数有限制,最终导 ...
- 使用Flask开发简单接口(3)--引入MySQL
前言 前面的两篇文章中,我们已经学习了通过Flask开发GET和POST请求接口,但一直没有实现操作数据库,那么我们今天的目的,就是学习如何将MySQL数据库运用到当前的接口项目中. 本人环境:Pyt ...
- 使用Flask开发简单接口(5)--数据加密处理
前言 在之前开发的接口中,我们设计把用户信息存储到数据库时,没有对数据进行加密处理,为了提高下安全性,我们今天就学习下,如何对用户数据进行加密加盐处理. MD5加密加盐 MD5加密 MD5是常用的一种 ...
- 使用Flask开发简单接口
作为测试人员,在工作或者学习的过程中,有时会没有可以调用的现成的接口,导致我们的代码没法调试跑通的情况. 这时,我们使用python中的web框架Flask就可以很方便的编写简单的接口,用于调用或调试 ...
- 使用Django开发简单接口:文章增删改查
目录 1.一些准备工作 安装django 创建django项目 创建博客应用(app) 2.models.py 3.django admin 登录 创建超级用户 4.修改urls.py 5.新增文章接 ...
- koa2+redis+jwt token验证,简单注册登录
首先新建文件夹命名koa-server,npm init,相关包的安装就不说了,这是我的package.json 新建index.js文件,编码如下,config全局配置不用管,redis是一个简单的 ...
- PHP开发APP接口实现--基本篇
最近一段时间一直在做APP接口,总结一下APP接口开发以来的心得,与大家分享: 1. 客户端/服务器接口请求流程: 安卓/IOS客户端 –> PHP接口 –> 服务器端 –> ...
- NodeJS 微信公共号开发 - 响应微信发送的Token验证(山东数漫江湖)
背景 使用 NodeJS 进行微信公共号开发,首先需要响应微信发送的Token验证,官方文档 填写服务器配置 登录微信公共平台,在开发下的基本配置打开该页面. 依次填写接口的 URL.自定义的 Tok ...
随机推荐
- (二)学习了解OrchardCore笔记——开篇:OrchardCore的中间件
现在开始看Starpup的中间件.这是一个扩展方法app.UseOrchardCore() public void Configure(IApplicationBuilder app, IHostEn ...
- MYSQL 之 JDBC(十二): 处理Blob
LOB,即Large Objects(大对象),是用来存储大量的二进制和文本数据的一种数据类型 LOB分为两种内省:内部LOB和外部LOB 内部LOB将数据以字节流的形式存储在数据库的内部.因而内部L ...
- python数据处理(八)之展示数据
1.前言 1.1.不要擅自假定要讲的故事和数据是一致的,要先研究数据,然后讲述数据研究所得 1.2.讲故事是成为领域专家的重要部分. 1.3.将故事方法: a. 确定想要讲的故事 b.无论选择什么方式 ...
- TCP 和 UDP,哪个更胜一筹
作为 TCP/IP 中两个最具有代表性的传输层协议,TCP 和 UDP 经常被拿出来相互比较.这些协议具体有什么区别,又是什么作用呢? 在 IT 圈混迹多年的小伙伴们,对 TCP 和 UDP 肯定再熟 ...
- UVA1104 芯片难题 Chips Challenge
题目链接 题意 网格上放点,有些强制放,有些不能放,有些可以放可以不放.要求: 第 \(i\) 行的点数 = 第 \(i\) 列的点数 每一行每一列的点数不超过总点数的 \(k\) 倍(\(k\) 已 ...
- 常用核心数据库查询sql
一.查询账户信息 -- 查询数据量 /*{"xdb_comment":"1","table":"mb_tran_hist" ...
- List<Activity> lists的关闭finish()
public class App extends Application { private static List<Activity> lists = new ArrayList< ...
- 使用matlab进行傅里叶分析和滤波
傅里叶分析 公式法 下例 是将振幅为1的5Hz正弦波和振幅为0.5的10Hz正弦波相加之后进行傅里叶分析. clear all N=512; dt=0.02; n=0:N-1; t=n*dt; x=s ...
- 使用types库修改函数
import types class ppp: pass p = ppp()#p为ppp类实例对象 def run(self): print("run函数") r = types. ...
- Excel绘制动态图表 之 极品offset、多种控件动态动图
1.案例1:辅助区域动态图 动态按钮“投资金额”的制作: "数据"菜单下"数据工作”组中的“数据验证”,选择"序列". 2. OFFSET ——函数中 ...