在以前开发的接口中,咱们设计把用户信息存储到数据库时,没有对数据进行加密处理,为了提升下安全性,咱们今天就学习下,如何对用户数据进行加密加盐处理。git
MD5是经常使用的一种加密方法,它具备不可逆性,也就是说它只能加密,而不能进行解密,相对较安全。若是须要在Python3中使用MD5加密,直接使用内建模块 hashlib
就好了,无需额外安装。github
咱们以前设置的 password
密码是明文的,好比 123456,这个是没有进行加密的,若是使用MD5加密后是这样的:redis
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加密,另外,由于咱们当前设计的用户名是惟一且没法修改的,因此能够把用户名也放进去进行加密处理,以提升用户密码的安全性。sql
咱们在项目根路径下 config
包中,修改文件 setting.py
,在该文件中配置MD5加密加盐处理的盐值 SALT
,以下:数据库
SALT = "test2020#%*"
同时,咱们在项目根路径下 common
包中,新建文件 md5_operate.py
,该文件下存放了 MD5加密加盐
的代码,以下:json
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() # 返回密文
@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加密,而后把密文用于注册并写入到数据库中。flask
@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
几个字段的数据。app
这个接口是经过 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