接口加密处理

如何处理接口加密,主要看开发用的什么方法,接口文档时怎么规定的,这里只是其中的一种加密方法介绍,用的是RSA方法进行加密,先来看一下接口文档

接口加密处理_第1张图片

当 X-Lemonban-Media-Type 请求头值为 lemonban.v3 时,接口使用 timestamp+token+sign 鉴权

关于什么是token,什么是sign,可以参考此篇文章:

session和token鉴权方式_晒不黑的黑煤球的博客-CSDN博客

需要进行如下设置:

  1.  设置 Authorization 请求头,值为 Bearer token 值
  2.  请求体 json 设置 timestamp 参数,值为当前时间戳,类型为 long
  3.  请求体 json 设置 sign 参数,取 token 前 50 位再拼接上 timestamp 值,然后通过 RSA 公钥加密得到的字符串

接口加密处理_第2张图片

具体代码操作如下:

修改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)

运行结果:

接口加密处理_第3张图片

你可能感兴趣的:(接口,python,rsa)