进阶问题
1、接口返回:用户未登录——session处理
2、接口返回:验签失败——参数签名
3、接口返回:解密失败——参数加密
在接口测试框架搭建的时候,这些问题难免会劝退不少人。问题1是需要进行参数传递,将登录成功后的session保存下来,并在后续的业务接口中复用;问题2和3,则需要花时间研究接口脚本,理解签名原理和加密方法,然后编写签名和加密的方法。
假设:初始化(无加密字段)→登录请求(密码加密)→业务请求
不难分析出来,首先会遇到的问题是参数签名,然后是参数加密,最后是session。
参数签名
参数签名需要参考接口文档,但大体还是类似的,只会存在一些小的差异。
举个例子:
1、添加请求参数:temp,值为13位的时间戳;
2、对所有请求的非空参数按key的ascii码排序;
3、按“key=value”格式并已“&”进行拼接,并在最后拼接上秘钥“key=XXX”;
4、将拼接好的字符串进行MD5加密并将密文转成大写;
5、添加请求参数:sign,值为MD5密文。
所以,我们需要设计一个方法,传入原始的请求参数,返回签名后的参数。
import time, hashlib
def Sign_data(dict):
signKey = "test_key_1234567" #签名秘钥
temp ="CS" +str(int(time.time() *1000))
dict["temp"] = temp #拼接时间戳
dict_temp = dict
list_temp =sorted(dict_temp.keys())
for key in list_temp: #去除值为空的key
if dict_temp[key] =="":
del dict_temp[key]
list_temp =sorted(dict_temp.keys()) #创建key的列表,并排序
string =""
for list_temp_key in list_temp: #拼接待签名字符串
string = string + list_temp_key +"=" +str(dict_temp[list_temp_key]) +"&"
string = string +"key=" + signKey #拼接秘钥
try: #进行MD5签名及转换大写,并将签名值并入请求参数
sign = hashlib.md5(string.encode("utf-8")).hexdigest().upper()
dict["sign"] = sign
except:
print('Sign Error!!')
return dict
签名前:{'account': 'admin', 'password': 'a123456'}
签名后:{'account': 'admin', 'password': 'a123456', 'temp': 'CS1601346355016', 'sign': '52C0A0CA2F2EA451DEFF011D5F3AA2AA'}
参数加密
对于一些重要的信息,如:密码、银行卡账号、手机号码、邮箱等隐私信息。是需要加密后再传输的,以免数据被窃取导致重要信息泄露。尤其是支付密码等重要信息,对加密要求更加重视。
这里举个简单的例子,对隐私信息,需要进行3DES加密后,再签名。
import base64
from Crypto.Cipher import DES3
BS = DES3.block_size
def _pad(value):
return value + (BS - len(value) % BS) * chr(BS - len(value) % BS)
def _3DES(value):
signKey = "test_key_1234567"
value = _pad(value)
crypto_des3 = DES3.new(signKey, DES3.MODE_ECB)
x = len(value) % 8
if x != 0:
value = value + '\0' * (8 - x)
ciphervalue = crypto_des3.encrypt(value)
return base64.standard_b64encode(ciphervalue).decode("utf-8")
加密前:a123456
加密后:elnNMd0ac4M=
封装方法
在编译器已经将加密和签名的方法都已经编写完成,方法需要在RobotFramework里使用,需要进行封装处理。
创建Python Package,命名为SignMethord,文件夹内创建Python文件,命名signMethord.py。
1、signMethod.py 定义一个类SignMethod,并将前面的加密函数添加进入类
import time, hashlib, base64
from Crypto.Cipherimport DES3
BS = DES3.block_size
class SignMethod(object):
def _pad(self, s):
return s + (BS -len(s) % BS) *chr(BS -len(s) % BS)
def _3DES(self, value):
signKey ="test_key_1234567" # 签名秘钥
value = SignMethod()._pad(value)
crypto_des3 = DES3.new(signKey, DES3.MODE_ECB)
x =len(value) %8
if x !=0:
value = value +'\0' * (8 - x)
ciphervalue = crypto_des3.encrypt(value)
return base64.standard_b64encode(ciphervalue).decode("utf-8")
def Sign_data(self, dict):
signKey ="test_key_1234567" # 签名秘钥
temp ="CS" +str(int(time.time() *1000))
dict["temp"] = temp# 拼接时间戳
dict_temp = dict
list_temp =sorted(dict_temp.keys())
for key in list_temp:# 去除值为空的key
if dict_temp[key] =="":
del dict_temp[key]
list_temp_key =list(set(dict_temp.keys()).intersection({'password','phone','cardId'})) #获取请求参数中需要加密的key
if len(list_temp_key) !=0:
for temp_keyin list_temp_key:
dict_temp[temp_key] = SignMethod()._3DES(dict_temp[temp_key])
list_temp =sorted(dict_temp.keys())# 创建key的列表,并排序
string =""
for list_temp_key in list_temp:# 拼接待签名字符串
string = string + list_temp_key +"=" +str(dict_temp[list_temp_key]) +"&"
string = string +"key=" + signKey# 拼接秘钥
try:# 进行MD5签名及转换大写,并将签名值并入请求参数
sign = hashlib.md5(string.encode("utf-8")).hexdigest().upper()
dict["sign"] = sign
except:
print('Sign Error!!')
return dict
#主函数,调试
if __name__ =="__main__":
Sign = SignMethod()
data = {"account":"admin",
"password":"a123456"}
print(data)
print(Sign.Sign_data(data))
处理前:{'account': 'admin', 'password': 'a123456'}
处理后:{'account': 'admin', 'password': 'elnNMd0ac4M=', 'temp': 'CS1601351366732', 'sign': 'BB94E448E5A3848A547332EBB643CB11'}
2、__init__.py
from .signMethod import SignMethod
class SignMethod(SignMethod):
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
文件编辑完成后,将文件夹移动到python目录下的/site-package目录内,即可在RobotFramework内调用该方法
加入SignMethod 参数加密签名运行结果如下:
Starting test: Rf test.Rf mian.test
20200929 14:01:38.920 : INFO : &{data} = { account=admin | password=a123456 }
20200929 14:01:38.921 : INFO : &{data} = { account=admin | password=elnNMd0ac4M= | temp=CS1601359298919 | sign=D469F8D02FDBF95B0D4116BC38826551 }
Ending test: Rf test.Rf mian.test
到这一步,就完成了接口请求参数的加密和签名。各项目的加密方法会不一样,签名方式也存在一定的区别,这个需要自己花点时间去研究。甚至,在做加密集成的时候,还会踩出不少坑。例如,在3DES加密的时候,需要用到Crypto的第三方库,这个库在windows上安装是需要C++的基础环境的依赖,需要另外安装,这个就是其中一个采坑的经历。然而,在linux安装则可以直接使用pip安装即可。当然也有另外的库可以取代:pycryptodome
Session处理
1、初始化后,获取返回的session值并存入headers
2、使用新的headers进行登录
2、使用带session的headers进行登录3、登录成功后,即可使用该session进行后续业务接口的访问
3、使用已登录的session,进行修改用户昵称操作注意:session存在有效期
到此为止,就可以开始真正意义上的接口测试了!
网友评论