1. 参数加密
在测试过程中遇到参数加密,有两种方案:
- 找开发协调,提供加密的模块,例如
jar包
,然后通过python去调用。见博客 - 找开发了解加密的过程,自己用python代码封装
时间戳:某个时刻距离1970 01 01 0: 0: 0 的秒数
import time
time.time()
1639397535.4410264
2. RSA加密
2.1 RSA加密原理
非对称加密的一种。
所谓的非对称加密,加密秘钥和解密秘钥不一样。
根据数论,寻求两个大的素数比较简单,但是把它们的乘积进行因式分解却极其困难,因此,可以将乘积公开作为加密秘钥。
非对称加密一般用来做身份验证和端数据加密(非对称加密加密速度,加密数据大小有限)
2.2 RSA库
- 安装
pip install rsa
- 使用
# 生成秘钥对
import rsa
pub, pri = rsa.newkeys(1024)
# 数字1024表示生成1024位的密钥。你也可以写2048或者4096
# 位数越多越安全,但是加密解密速度越慢。
# RSA 加密对被加密的内容(明文)是有长度限制的。
# 因为最终的密文中会有11 bytes 的内容用来存放加密相关的元信息,
# 所以对于1024位的密钥来说,能加密的明文长度为1024\div8-11=117bytes。
print(pub)
输出
PublicKey(116308441139083577876157766248745833179967747901846507416595813990199342503462594660347616002313121632810925952593865864943639914938330483050483584606533608782756061411525819545781619361567454572833959557870861076026031268593353966696612026141092181598777033352851699891932171227194324855047825969171482077269, 65537)
print(pri)
输出
PrivateKey(116308441139083577876157766248745833179967747901846507416595813990199342503462594660347616002313121632810925952593865864943639914938330483050483584606533608782756061411525819545781619361567454572833959557870861076026031268593353966696612026141092181598777033352851699891932171227194324855047825969171482077269, 65537, 61301649050555029174332690873310932293245738255116683082595367606839887220266489841734094510763383240620641839792747832627114606127833308597125326148143893920294887461021330211253959497007343944186201963266225852224192388755240384507953577780376651340580793278942579060402934814213057298957100845605139428777, 42837935774961484388279765551600265000598506992169151065321761561502872335981777864293843463598590806801192583926530272172222974901527411630998148154819045349716183, 2715080431281312150476471084253311429987757187834481444213286099681552767626583562417088850641154058312803528888629807558190124397045603405745843)
# 加密
# 消息加密之前,需要转换成字节数据
message = '心蓝'.encode('utf-8')
res = rsa.encrypt(message, pub)
print(res)
b'}7\x1b\x0eb\xc6\x8f\xd0y\xbbw\xbc>\xe3\x95r\x8d\xd7\xee\xe9\xc3\xc7&:`\xb3\xc1\xaa\xde\xb1\xd5\x04\x16\xa6\x9d\x88\xa8\xfb\xf0\x12\x0cc.\x9c\xcb\xf1\xba\xdc&\x11\xfb \xaeH\xee\x0fn?p7\xcfj\\\xfb[\xce\xc1\x87jl\xc7\x92\x82\xaa r\xc4\x95`\x84\x80\xfcR\xb1\xf4\x17B\x00\xd31_\xd1(\xbd*\x1f\x11ws\xc3\xae\xf6vE\xd3\xb5/\xbaI\x19`R\x90C\x97\xaf\x81\xf5A_Q\x9b\xf76\xa7\xf3\xa9\x04'
# 一般加密的密文会以base64编码的方式输出
# a-z A-Z 0-9 += 26+26+10+2 64
import base64
b_res = base64.b64encode(res).decode()
b_res
输出
'fTcbDmLGj9B5u3e8PuOVco3X7unDxyY6YLPBqt6x1QQWpp2IqPvwEgxjLpzL8brcJhH7IK5I7g9uP3A3z2pc+1vOwYdqbMeSgqogcsSVYISA/FKx9BdCANMxX9EovSofEXdzw672dkXTtS+6SRlgUpBDl6+B9UFfUZv3NqfzqQQ='
base64.b64decode(b_res.encode())
输出
b'}7\x1b\x0eb\xc6\x8f\xd0y\xbbw\xbc>\xe3\x95r\x8d\xd7\xee\xe9\xc3\xc7&:`\xb3\xc1\xaa\xde\xb1\xd5\x04\x16\xa6\x9d\x88\xa8\xfb\xf0\x12\x0cc.\x9c\xcb\xf1\xba\xdc&\x11\xfb \xaeH\xee\x0fn?p7\xcfj\\\xfb[\xce\xc1\x87jl\xc7\x92\x82\xaa r\xc4\x95`\x84\x80\xfcR\xb1\xf4\x17B\x00\xd31_\xd1(\xbd*\x1f\x11ws\xc3\xae\xf6vE\xd3\xb5/\xbaI\x19`R\x90C\x97\xaf\x81\xf5A_Q\x9b\xf76\xa7\xf3\xa9\x04'
# 解密
# 注意解密的数据是二进制数据
# base64编码的数据要转换成二进制数
rsa.decrypt(base64.b64decode(b_res.encode()), pri)
输出
b'\xe5\xbf\x83\xe8\x93\x9d'
b'\xe5\xbf\x83\xe8\x93\x9d'.decode('utf8')
输出
'心蓝'
读取现有的公钥
pub_key = """
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQENQujkLfZfc5Tu9Z1LprzedE
O3F7gs+7bzrgPsMl29LX8UoPYvIG8C604CprBQ4FkfnJpnhWu2lvUB0WZyLq6sBr
tuPorOc42+gLnFfyhJAwdZB6SqWfDg7bW+jNe5Ki1DtU7z8uF6Gx+blEMGo8Dg+S
kKlZFc8Br7SHtbL2tQIDAQAB
-----END PUBLIC KEY-----
"""
# 一般提供的公钥的格式都是pem格式
# 1. 转换成字节数据
pub_key = pub_key.encode()
# 2. 调用方法加载
pub = rsa.PublicKey.load_pkcs1_openssl_pem(pub_key)
pub
PublicKey(146108729746987381736834158701459520580739497972013422621519958953375798933355627739500199234753023982343910387697136163975815556804841172178573058935486832130715154287652170649213576078798069230216422090889080187686092667825252542151372336410071790576887605716209248483695097952444145927616731433244959110837, 65537)
3. 封装v3版本token签名函数
-
在settings.py中添加公钥配置
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2021/11/17 20:27 # @Author : shisuiyi # @File : setting.py # @Software: win10 Tensorflow1.13.1 python3.9 # 服务器公钥 SERVER_RSA_PUB_KEY = """ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQENQujkLfZfc5Tu9Z1LprzedE O3F7gs+7bzrgPsMl29LX8UoPYvIG8C604CprBQ4FkfnJpnhWu2lvUB0WZyLq6sBr tuPorOc42+gLnFfyhJAwdZB6SqWfDg7bW+jNe5Ki1DtU7z8uF6Gx+blEMGo8Dg+S kKlZFc8Br7SHtbL2tQIDAQAB -----END PUBLIC KEY----- """
4. v3版本的投资接口测试
4.1 用例数据设计
根据上节课将的业务流的方案2,接口的前置条件我们也可以看做是一条用例,实现完全的数据驱动。
4.2 用例类代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/12/14 20:40
# @Author : shisuiyi
# @File : encrypt_handler.py
# @Software: win10 Tensorflow1.13.1 python3.9
import base64
import time
import rsa
def rsa_encrypt(msg: str, server_pub_key: str):
"""
公钥加密
:param msg: 要加密的字符串内容
:param server_pub_key: pem格式的公钥字符串
:return:
"""
# 生成公钥对象:将公钥编码并加载
pub_key_obj = rsa.PublicKey.load_pkcs1_openssl_pem(server_pub_key.encode())
# 要加密的数据转换成字节对象
content = msg.encode('utf-8')
# 加密
crypt_msg = rsa.encrypt(content, pub_key_obj)
# bas464编码密文,并转成字符串格式
return base64.b64encode(crypt_msg).decode()
def generate_sign(token, pub_key):
"""
生成签名
:param token: token字符串
:param pub_key: pem格式的公钥字符串
:return:
"""
# 获取token 的前50位
token_50 = token[:50]
# 生成整数时间戳
timestamp = int(time.time())
# 拼接前50位和时间戳
msg = token_50 + str(timestamp)
# 进行RSA加密
sign = rsa_encrypt(msg, pub_key)
return sign, timestamp
if __name__ == '__main__':
import setting
token_str = "eyJhbGciOiJIUzUxMiJ9.eyJtZW1iZXJfaWQiOjM0Njc0NzAsImV4cCI6MTYzOTQ4NjQwMX0.y9hjmhix7ri4aGPoYVKShIRGvipFFwafFuHAwOrlSmySdjIqyxMMe6GIbXUZYxaJg4ZiGTQCV6Qubp-YYLGKSg"
sign, timestamp = generate_sign(token_str, setting.SERVER_RSA_PUB_KEY)
print(sign, timestamp)
4.3 多表校验
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/12/11 11:12
# @Author : shisuiyi
# @File : base_case.py
# @Software: win10 Tensorflow1.13.1 python3.9
# 前略``
def assert_sql(self):
"""
断言数据库
"""
if self._case.get('sql'): # 返回指定键的值,如果键不在字典中返回默认值 None 或者设置的默认值。
# 只有sql字段有sql的才需要校验数据库
# 只有sql字段有sql的才需要校验数据库
sqls = self._case['sql'].split(',')
for sql in sqls:
try:
self.assertTrue(self.db.exist(sql))
except AssertionError as e:
self.logger.warning('用例【{}】数据库断言异常,执行的sql为:{}'.format(self._case['title'], sql))
raise e
except Exception as e:
self.logger.warning('用例【{}】数据库断言异常,执行的sql为:{}'.format(self._case['title'], sql))
raise e
在测试数据的处理中添加鉴权
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/12/11 11:12
# @Author : shisuiyi
# @File : base_case.py
# @Software: win10 Tensorflow1.13.1 python3.9
# 前略``
def process_test(self):
"""
测试数据的处理
"""
# 1.1 生成测试数据
self.generate_test_data()
# 1.2 替换依赖参数
self.replace_args()
# 1.3 处理url
self.process_url()
# 1.4 鉴权处理
self.auth_process()
def auth_process(self):
"""
v3版本鉴权处理
:return:
"""
if self._case['request_data']['headers']['X-Lemonban-Media-Type'] == 'lemonban.v3':
# 获取token
token = self._case['request_data']['headers']['Authorization'].split(' ')[-1]
# 生成签名
sign, timestamp = generate_sign(token, self.setting.SERVER_RSA_PUB_KEY)
# 添加到请求数据中
self._case['request_data']['json']['sign'] = sign
self._case['request_data']['json']['timestamp'] = timestamp
总结:
- 为了实现v3版本,在数据处理的流程中增加了auth_process的方法,根据实际情况,怎么方便实现怎么来。如果实际项目做不到完全统一,那么在特殊的接口测试用例中,复写对应的方法即可。
- 本项目的业务逻辑相对简单,所以设计的sql都是校验是否存在,实际项目可能比较复杂。可以根据不同接口不用sql校验逻辑,不用强行封装,减少难度。