1. 参数加密

在测试过程中遇到参数加密,有两种方案:

  1. 找开发协调,提供加密的模块,例如jar包,然后通过python去调用。见博客
  2. 找开发了解加密的过程,自己用python代码封装

时间戳:某个时刻距离1970 01 01 0: 0: 0 的秒数

import time
time.time()
1639397535.4410264

2. RSA加密

2.1 RSA加密原理

非对称加密的一种。

所谓的非对称加密,加密秘钥和解密秘钥不一样。

根据数论,寻求两个大的素数比较简单,但是把它们的乘积进行因式分解却极其困难,因此,可以将乘积公开作为加密秘钥。

非对称加密一般用来做身份验证和端数据加密(非对称加密加密速度,加密数据大小有限)

2.2 RSA库

  1. 安装
    • pip install rsa
  2. 使用
# 生成秘钥对
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签名函数

  1. 在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

总结:

  1. 为了实现v3版本,在数据处理的流程中增加了auth_process的方法,根据实际情况,怎么方便实现怎么来。如果实际项目做不到完全统一,那么在特殊的接口测试用例中,复写对应的方法即可。
  2. 本项目的业务逻辑相对简单,所以设计的sql都是校验是否存在,实际项目可能比较复杂。可以根据不同接口不用sql校验逻辑,不用强行封装,减少难度。