前言

在之前开发的接口中,我们设计把用户信息存储到数据库时,没有对数据进行加密处理,为了提高下安全性,我们今天就学习下,如何对用户数据进行加密加盐处理。

MD5加密加盐

  • MD5加密

MD5是常用的一种加密方法,它具有不可逆性,也就是说它只能加密,而不能进行解密,相对较安全。如果需要在Python3中使用MD5加密,直接使用内建模块 hashlib 就行了,无需额外安装。

我们之前设置的 password 密码是明文的,比如 123456,这个是没有进行加密的,如果使用MD5加密后是这样的:

import hashlib

def get_md5(str):
"""MD5加密处理"""
md5 = hashlib.md5() # 创建md5对象
md5.update(str.encode("utf-8")) # Python3中需要先转换为 bytes 类型,才能加密
return md5.hexdigest() # 返回密文 password = "123456"
print("MD5加密前:{}".format(password)) # 123456
md5_pwd = get_md5((password))
print("MD5加密后:{}".format(md5_pwd)) # e10adc3949ba59abbe56e057f20f883e
  • 加盐

加盐,是指通过对原始用户密码加一个复杂字符串后,然后再进行MD5加密,另外,因为我们当前设计的用户名是唯一且无法修改的,所以可以把用户名也放进去进行加密处理,以提高用户密码的安全性。

我们在项目根路径下 config 包中,修改文件 setting.py ,在该文件中配置MD5加密加盐处理的盐值 SALT,如下:

SALT = "test2020#%*"

同时,我们在项目根路径下 common 包中,新建文件 md5_operate.py ,该文件下存放了 MD5加密加盐 的代码,如下:

import hashlib
from config.setting import MD5_SALT def get_md5(username, str):
"""MD5加密处理"""
str = username + str + MD5_SALT # 把用户名也作为str加密的一部分
md5 = hashlib.md5() # 创建md5对象
md5.update(str.encode("utf-8")) # Python3中需要先转换为 bytes 类型,才能加密
return md5.hexdigest() # 返回密文

注册用户时MD5加密

@app.route("/register", methods=['POST'])
def user_register():
"""注册用户"""
username = request.json.get("username", "").strip() # 用户名
password = request.json.get("password", "").strip() # 密码
sex = request.json.get("sex", "0").strip() # 性别,默认为0(男性)
telephone = request.json.get("telephone", "").strip() # 手机号
address = request.json.get("address", "").strip() # 地址,默认为空串
if username and password and telephone: # 注意if条件中 "" 也是空, 按False处理
sql1 = "SELECT username FROM user WHERE username = '{}'".format(username)
res1 = db.select_db(sql1)
print("查询到用户名 ==>> {}".format(res1))
sql2 = "SELECT telephone FROM user WHERE telephone = '{}'".format(telephone)
res2 = db.select_db(sql2)
print("查询到手机号 ==>> {}".format(res2))
if res1:
return jsonify({"code": 2002, "msg": "用户名已存在,注册失败!!!"})
elif not (sex == "0" or sex == "1"):
return jsonify({"code": 2003, "msg": "输入的性别只能是 0(男) 或 1(女)!!!"})
elif not (len(telephone) == 11 and re.match("^1[3,5,7,8]\d{9}$", telephone)):
return jsonify({"code": 2004, "msg": "手机号格式不正确!!!"})
elif res2:
return jsonify({"code": 2005, "msg": "手机号已被注册!!!"})
else:
password = get_md5(username, password) # 把传入的明文密码通过MD5加密变为密文,然后再进行注册
sql3 = "INSERT INTO user(username, password, role, sex, telephone, address) " \
"VALUES('{}', '{}', '1', '{}', '{}', '{}')".format(username, password, sex, telephone, address)
db.execute_db(sql3)
print("新增用户信息SQL ==>> {}".format(sql3))
return jsonify({"code": 0, "msg": "恭喜,注册成功!"})
else:
return jsonify({"code": 2001, "msg": "用户名/密码/手机号不能为空,请检查!!!"})

在上面代码中,我们只在注册之前增加了一行代码:password = get_md5(username, password),先把请求参数中传入的明文密码进行MD5加密,然后把密文用于注册并写入到数据库中。

登录用户时MD5加密

@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": "用户名不存在!!!"})
md5_password = get_md5(username, password) # 把传入的明文密码通过MD5加密变为密文
sql2 = "SELECT * FROM user WHERE username = '{}' and password = '{}'".format(username, md5_password)
res2 = db.select_db(sql2)
print("获取 {} 用户信息 == >> {}".format(username, res2))
if res2:
timeStamp = int(time.time()) # 获取当前时间戳
# token = "{}{}".format(username, timeStamp)
token = get_md5(username, str(timeStamp)) # MD5加密后得到token
redis_db.handle_redis_token(username, token) # 把token放到redis中存储
return_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": return_info, "msg": "恭喜,登录成功!"})
return jsonify({"code": 1002, "msg": "用户名或密码错误!!!"})
else:
return jsonify({"code": 1001, "msg": "用户名或密码不能为空!!!"})

上面代码中,我们在登录前对请求参数中的明文密码进行MD5加密:md5_password = get_md5(username, password),然后再进行登录,而登录成功后,同样先对 token 进行MD5加密:token = get_md5(username, str(timeStamp)),再存储到redis中。

修改用户请求接口实现

接下来,我们准备新开发个接口:修改用户接口。该接口需要 管理员用户 登录认证后才可以进行操作,管理员用户可以修改任何用户信息。但在修改用户信息时,只允许修改 密码 password、性别 sex、手机号 telephone、联系地址 address 几个字段的数据。

  • 修改用户接口(PUT接口)

这个接口是通过 PUT 方式来进行请求,在 Flask 中,如果要让请求接口接口支持 PUT 请求方式,我们只需要在 methods 中设置就行。

@app.route("/update/user/<int:id>", methods=['PUT'])
def user_update(id): # id为准备修改的用户ID
"""修改用户信息"""
username = request.json.get("username", "").strip() # 当前登录的管理员用户
token = request.json.get("token", "").strip() # token口令
new_password = request.json.get("password", "").strip() # 新的密码
new_sex = request.json.get("sex", "0").strip() # 新的性别,如果参数不传sex,那么默认为0(男性)
new_telephone = request.json.get("telephone", "").strip() # 新的手机号
new_address = request.json.get("address", "").strip() # 新的联系地址,默认为空串
if username and token and new_password and new_telephone: # 注意if条件中空串 "" 也是空, 按False处理
if not (new_sex == "0" or new_sex == "1"):
return jsonify({"code": 4007, "msg": "输入的性别只能是 0(男) 或 1(女)!!!"})
elif not (len(new_telephone) == 11 and re.match("^1[3,5,7,8]\d{9}$", new_telephone)):
return jsonify({"code": 4008, "msg": "手机号格式不正确!!!"})
else:
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))
sql3 = "SELECT telephone FROM user WHERE telephone = '{}'".format(new_telephone)
res3 = db.select_db(sql3)
print("查询到手机号 ==>> {}".format(res3))
if not res2: # 如果要修改的用户不存在于数据库中,res2为空
return jsonify({"code": 4005, "msg": "修改的用户ID不存在,无法进行修改,请检查!!!"})
elif res3: # 如果要修改的手机号已经存在于数据库中,res3非空
return jsonify({"code": 4006, "msg": "手机号已被注册,无法进行修改,请检查!!!"})
else:
# 如果请求参数不传address,那么address字段不会被修改,仍为原值
if not new_address:
new_address = res2[0]["address"]
# 把传入的明文密码通过MD5加密变为密文
new_password = get_md5(res2[0]["username"], new_password)
sql3 = "UPDATE user SET password = '{}', sex = '{}', telephone = '{}', address = '{}' " \
"WHERE id = {}".format(new_password, new_sex, new_telephone, new_address, id)
db.execute_db(sql3)
print("修改用户信息SQL ==>> {}".format(sql3))
return jsonify({"code": 0, "msg": "恭喜,修改用户信息成功!"})
else:
return jsonify({"code": 4004, "msg": "当前用户不是管理员用户,无法进行操作,请检查!!!"})
else:
return jsonify({"code": 4003, "msg": "token口令不正确,请检查!!!"})
else:
return jsonify({"code": 4002, "msg": "当前用户未登录,请检查!!!"})
else:
return jsonify({"code": 4001, "msg": "管理员用户/token口令/密码/手机号不能为空,请检查!!!"})

相关的接口返回码和请求场景如下:

接口返回码 请求场景
0 请求参数正确,修改用户信息成功!
4001 请求参数中,管理员用户/token口令/密码/手机号,任一参数为空
4002 请求参数中,当前操作用户没有token,登录验证失败
4003 请求参数中的token值,与redis中的token值不一致
4004 请求参数中,当前操作用户不是管理员用户,无权限进行操作
4005 请求参数中,要删除的用户ID不存在
4006 请求参数中,手机号已被其他人注册使用
4007 请求参数中, sex 性别字段值不是 0 或 1
4008 请求参数中,手机号格式不正确

可参考如下进行修改用户接口请求( token 可以从用户登录成功后的接口返回数据中获取):

请求方式:PUT
请求地址:http://127.0.0.1:5000/update/user/3
请求头:
Content-Type: application/json Body:{"username": "wintest", "token": "f54f9d6ebba2c75d45ba00a8832cb593", "sex": "1", "address": "广州市天河区", "password": "12345678", "telephone": "13500010003"}

OK,通过以上操作,我们已成功对用户密码和token串进行了数据加密处理,并实现了修改用户的功能,相关代码已上传到GitHub,大家有兴趣的可以基于此进行学习及开展接口测试。

GitHub源码地址:https://github.com/wintests/flaskDemo

使用Flask开发简单接口(5)--数据加密处理的更多相关文章

  1. 使用Flask开发简单接口(2)--POST请求接口

    今天我们继续学习如何使用Flask开发POST接口:用户注册接口和用户登录接口. request接收参数 当我们在页面发出一个POST请求,请求传到服务器时,需要如何拿到当前请求的数据呢?在Flask ...

  2. 使用Flask开发简单接口(1)--GET请求接口

    前言 很多想学习接口测试的同学,可能在最开始的时候,常常会因没有可以练习的项目而苦恼,毕竟网上可以练习的接口项目不多,有些可能太简单了,有些可能又太复杂了,或者是网上一些免费接口请求次数有限制,最终导 ...

  3. 使用Flask开发简单接口(3)--引入MySQL

    前言 前面的两篇文章中,我们已经学习了通过Flask开发GET和POST请求接口,但一直没有实现操作数据库,那么我们今天的目的,就是学习如何将MySQL数据库运用到当前的接口项目中. 本人环境:Pyt ...

  4. 使用Flask开发简单接口(4)--借助Redis实现token验证

    前言 在之前我们已开发了几个接口,并且可以正常使用,那么今天我们将继续完善一下.我们注意到之前的接口,都是不需要进行任何验证就可以使用的,其实我们可以使用 token ,比如设置在修改或删除用户信息的 ...

  5. 使用Flask开发简单接口

    作为测试人员,在工作或者学习的过程中,有时会没有可以调用的现成的接口,导致我们的代码没法调试跑通的情况. 这时,我们使用python中的web框架Flask就可以很方便的编写简单的接口,用于调用或调试 ...

  6. 使用Django开发简单接口:文章增删改查

    目录 1.一些准备工作 安装django 创建django项目 创建博客应用(app) 2.models.py 3.django admin 登录 创建超级用户 4.修改urls.py 5.新增文章接 ...

  7. 在线支付接口之PHP支付宝接口开发简单介绍

    php100:92:在线支付接口之PHP支付宝接口开发 支付接口一般是第三方提供的代收款.付款的平台,可以通过支付接口帮助企业或个人利用一切可以使用的支付方式.常见支付平台:支付宝.快钱.云网支付.财 ...

  8. Java开发笔记(五十八)简单接口及其实现

    前面介绍了抽象方法及抽象类的用法,看似解决了不确定行为的方法定义,既然叫唤动作允许声明为抽象方法,那么飞翔.游泳也能声明为抽象方法,并且鸡类涵盖的物种不够多,最好把这些行为动作扩展到鸟类这个群体,于是 ...

  9. flask开发restful api系列(8)-再谈项目结构

    上一章,我们讲到,怎么用蓝图建造一个好的项目,今天我们继续深入.上一章中,我们所有的接口都写在view.py中,如果几十个,还稍微好管理一点,假如上百个,上千个,怎么找?所有接口堆在一起就显得杂乱无章 ...

随机推荐

  1. 接口测试基础——session认证和token认证

    总算是把这个过程理清楚了,现在我们的思路是:what?why?How?,实际上这些个机制产生的内部逻辑是从下至上的的:遇到问题了,想办法解决,总结归纳并取名.从解决一些小问题开始生长,不断打补丁直至完 ...

  2. php基础学习中认为重点的知识

    <?php ... ?> 简写成 <? ... ?> 服务器中可以通过php.ini中配置short_open_tag为on来实现 php语句必须以分号  ; 结尾 .  连接 ...

  3. java 面向对象(三十四):泛型三 自定义泛型类、泛型接口、泛型方法

    1.举例: [Order.java] public class Order<T> { String orderName; int orderId; //类的内部结构就可以使用类的泛型 T ...

  4. Python面向对象02/类的空间问题、类与对象之间的关系、类与类之间的关系

    Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 目录 Python面向对象02/类的空间问题.类与对象之间的关系.类与类之间的关系 1. 类的空间问题 2. 类与对象之间 ...

  5. networkX.core_number(graph)

    今天在学习别人特征工程的时候,看到这样一个函数,max_kcore = pd.DataFrame(list(nx.core_number(graph).items()), columns=[" ...

  6. 用CBrother脚本实现smtp协议发送一份邮件

    用CBrother脚本实现smtp协议发送一份邮件 之前用CBrother脚本写了一个拯救“小霸王服务器”的程序,公司人用着都挺好用,但是有时候谁重启了服务器其他人不知道,造成了多人多次重启,每个人都 ...

  7. CentOS开机启动不了修复

    1,如果启动时进度条,先修改为日志启动 启动后快速按任何键(Enter除外)进入如下界面 在按e进入 选择第二个选项卡 在按e进入将红色部分 rhgb quiet 删除,然后按Enter,在按b重启 ...

  8. 转自fineui论坛:解决fineui框架开发中的Designer.aspx.cs丢失问题

    在开发的时候碰到个问题,本来好好的Edit.aspx  Edit.aspx.cs  Edit.Designer.aspx.cs编辑Edit.aspx然后保存,编译的时候 发现Edit.aspx.cs里 ...

  9. 高效C++:模板和泛型编程

    模板和泛型编程的关注重点在编译期,所有的行为都在编译期确定,因此其规则和玩法也有自己特殊的一套,和其他模块不通用. 了解隐式接口和编译期多态 元编程------编译器多态,决定哪个重载函数被调用 cl ...

  10. 高效C++:让自己习惯C++

    视C++为一个联邦语言 面向过程,面向对象,泛型编程,元编程,C++同时支持,强大而迷惑 C++语言可以分为如下4个部分: C,C语言相同 C with Class,包括封装.继承.多态... Tem ...