如何处理接口加密,主要看开发用的什么方法,接口文档时怎么规定的,这里只是其中的一种加密方法介绍,用的是RSA方法进行加密,先来看一下接口文档
当 X-Lemonban-Media-Type 请求头值为 lemonban.v3 时,接口使用 timestamp+token+sign 鉴权
关于什么是token,什么是sign,可以参考此篇文章:
需要进行如下设置:
具体代码操作如下:
修改base.py代码如下:
import time
import rsa
import requests
import re
import json
from base64 import b64encode, decode
from config import config, secret_config
from jsonpath import jsonpath
class APICase:
# 我们去访问项目当中接口需要用到的独立的方法或属性
@classmethod
def login(cls):
# 访问登录接口(普通用户登录)
headers = {"X-Lemonban-Media-Type": "lemonban.v2"}
json_data = secret_config.user
login_resp = requests.request(url=config.host + 'member/login',
method='post',
headers=headers,
json=json_data).json()
cls.member_id = str(jsonpath(login_resp, '$..id')[0])
cls.token = jsonpath(login_resp, '$..token')[0]
cls.before_money = jsonpath(login_resp, '$..leave_amount')[0]
return (cls.member_id, cls.token, cls.before_money)
@classmethod
def admin_login(cls):
# 访问登录接口(管理员登录)
headers = {"X-Lemonban-Media-Type": "lemonban.v2"}
json_data = secret_config.admin_user
login_resp = requests.request(url=config.host + 'member/login',
method='post',
headers=headers,
json=json_data).json()
cls.admin_member_id = str(jsonpath(login_resp, '$..id')[0])
cls.admin_token = jsonpath(login_resp, '$..token')[0]
return (cls.admin_member_id, cls.admin_token)
@classmethod
def add_project(cls, token, member_id):
# 访问添加项目的接口
json_data = {"member_id": "10",
"title": "测试项目55",
"amount": 100000,
"loan_rate": 10.0,
"loan_date_type": 2,
"loan_term": 30,
"bidding_days": 5}
headers = {"X-Lemonban-Media-Type": "lemonban.v2",
"Authorization": f"Bearer {token}"}
add_resp = requests.request(url=config.host + '/loan/add',
method='post',
headers=headers,
json=json_data).json()
cls.loan_id = str(jsonpath(add_resp, '$..id')[0])
return add_resp
@classmethod
def replace_data(cls, string):
# 给指定的字符串替换成动态数据
result = re.finditer('#(.*?)#', string)
for i in result:
# i是匹配到的每个数据
old = i.group() # #member_id#
prop_name = i.group(1) # member_id
string = string.replace(old, str(getattr(cls, prop_name)))
return string
def prev_data(self, info):
# 数据替换
# 使用正则表达式替换json_data,headers中# #标记内容
json_data = info['json']
headers = info['headers']
json_data = self.replace_data(json_data)
headers = self.replace_data(headers)
# 转化成字典类型
json_data = json.loads(json_data)
headers = json.loads(headers)
expected = json.loads(info['expected'])
extractor = {}
if info['extractor']:
extractor = json.loads(info['extractor'])
# 将替换和转化之后的数据重新设置回字典的key,value
info['json'] = json_data
info['headers'] = headers
info['expected'] = expected
info['extractor'] = extractor
return info
def visit(self, info):
# 访问接口
resp = requests.request(url=config.host + info['url'],
method=info['method'],
headers=info['headers'],
json=info['json']).json()
return resp
@classmethod
def extract(cls, info, resp):
# 数据提取
for prcp_name, jsonpath_expression in info['extractor'].items():
value = jsonpath(resp, jsonpath_expression)[0]
# 设置类属性
setattr(cls, prcp_name, value)
def assert_all(self, info, resp):
# 断言
for key, value in info['expected'].items():
self.assertEqual(value, resp[key])
def steps(self, info):
info = self.prev_data(info)
resp = self.visit(info)
self.extract(info, resp)
self.assert_all(info, resp)
@staticmethod
def get_sign(ts, token):
# 取token前50位 + str(时间戳)
s = token[:50] + str(ts)
# 这是开发的公钥
key = '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQENQujkLfZfc5Tu9Z1LprzedE\nO3F7g s+7bzrgPsMl29LX8UoPYvIG8C604CprBQ4FkfnJpnhWu2lvUB0WZyLq6sBr\ntuPorOc42+gLnFfyhJAw dZB6SqWfDg7bW+jNe5Ki1DtU7z8uF6Gx+blEMGo8Dg+S\nkKlZFc8Br7SHtbL2tQIDAQAB\n-----END PUBLIC KEY-----\n'
# 加密过程
public_key = rsa.PublicKey.load_pkcs1_openssl_pem(key.encode())
enctypred = rsa.encrypt(s.encode(), public_key)
return b64encode(enctypred).decode()
def visit_v3(self, info):
# 接口使用 timestamp+token+sign 鉴权访问接口
headers = info['headers']
# 把原来测试用例中的v2修改成v3
headers['X-Lemonban-Media-Type'] = 'lemonban.v3'
data = info['json']
# 获取当时系统时间戳
ts = int(time.time())
# 判断请求头中是否有Authorization字段
if 'Authorization' in headers:
# 以空格把Bearer #token#分隔开,取token值
current_token = headers['Authorization'].split(' ')[1]
# 调用加密方法,需要传入时间戳及token
sign = self.get_sign(ts, current_token)
# 加密后,把timestamp和sign加入到请求体中
data['timestamp'] = ts
data['sign'] = sign
resp = requests.request(method=info['method'],
url=config.host + info['url'],
headers=headers,
json=data).json()
return resp
主要是加上V3版本的接口访问,及加密过程的方法,注意get_sign是个静态方法,所以括号中注意不加上self
投资接口直接修改成访问v3版本接口即可,其他没有变动,代码如下:
import unittest
from config import secret_config, config
from ddt import ddt, data
from common.excel import read_excel
from common.base import APICase
from common.logger import log
# 得到测试数据
excel_data = read_excel(file_name=config.cases_dir, sheet_name='invest')
@ddt
class TestInvest(unittest.TestCase, APICase):
@classmethod
def setUpClass(cls) -> None:
# 直接从配置文件中读取需要的数据,然后设置成APICase属性
cls.investor_phone = secret_config.user['mobile_phone']
cls.investor_pwd = secret_config.user['pwd']
cls.loan_phone = secret_config.user['mobile_phone']
cls.loan_pwd = secret_config.user['pwd']
cls.admin_phone = secret_config.admin_user['mobile_phone']
cls.admin_pwd = secret_config.admin_user['pwd']
@data(*excel_data)
def test_invest(self, info):
# 四步操作:1.数据准备,2.访问接口,3.数据预处理,4.断言
info = self.prev_data(info)
# 调用v3版本的访问接口方法
resp = self.visit_v3(info)
self.extract(info, resp)
self.assert_all(info, resp)
运行结果: