一, 背景
最近负责的项目接口签名规则做了调整, 第一次接触 "2 次认证" 的方式, 正好有时间, 记录一下.
测试的服务 A 有一部分接口需要给第三方调用, 这样需要对第三方有个认证, 认证是由一个公共服务 (API 鉴权服务) 来完成的.
第三方调用服务 A 的认证流程:
1, 先访问 API 鉴权服务来获取 apiToken(即拿到访问服务 A 的认证)
2, 再由获取到的 apiToken 参与服务 A 的签名认证规则
这样就相当于在第三方和服务 A 直接增加了 2 次认证, 安全性有了更好的保障.
流程 1(获取 apiToken)的签名规则如下:
, 将所有请求参数的值放入 List 中, 注意: 计算 sign 时所有参数不应进行 URLEncode;
, 将格式化后的参数以字典序升序排列, 拼接在一起, 注意字典序中大写字母在前, 空值 (null) 使用空字符串代替;
, 将 B 形成字符串获取 SHA1 摘要, 形成一个 40 位的十六进制 (字母大写) 字符串, 即为本次请求 signature(签名)的值;
流程 2(获取服务 A 的签名)的规则如下:
, 参与签名的参数为: apiToken+appKey+appSecret+timestamp+body(提取 body 中的所有参数)
, 将格式化后的参数以字典序升序排列, 拼接在一起
, 将第二步形成字符串获取 SHA1 摘要
, 第三步获得的字符串即为签名参数
二, 代码实现
规则同时也是签名的构造方法, 按照上面所列的步骤用 Python 来实现.
获取 apiToken:
请求参数有 3 个:
appKey: 应用 KEY(必填项)
timestamp: 访问时间戳(必填项),Unix 时间戳;
signature: 签名(必填项)
- """
- Created on 2019 年 04 月 03 日
- @author:
- """
- import time
- import hashlib
- import requests
- import operator
- import JSON
- appKey = "n3nuk67byade3c3qgrccjhosvmqfzt7z5wavp3ig"
- appSecret = "b3a3056ef7ffb441332892ed76998b2e"
- time_stamp = str(int(time.time()))
- url = "http://10.10.10.100:8080/rest/v1/token/get"
- class get_tokenclass():
- # 生成字符串
- def str_create(self):
- if operator.lt(appKey[0], appSecret[0]) == bool(1): #py3 中 operator 类和 py2 中 cmp()函数的作用相似, 通过比较 2 个值的大小, 返回布尔类型
- strnew = time_stamp + appKey + appSecret
- else:
- strnew = time_stamp + appSecret + appKey
- print(strnew)
- return strnew
- # 生成 signature
- def signature_create(self):
- str_switch = self.str_create()
- signature = hashlib.sha1(str_switch.encode('utf-8')).hexdigest().upper().strip()
- print(signature)
- return signature
- # 生成 token
- def token_creat(self):
- signature = self.signature_create()
- params = {"appKey":appKey, "timestamp":time_stamp, "signature":signature}
- res = requests.get(url=url,params=params)
- print(res.url)
- print(JSON.loads(res.content.decode('utf-8')))
- token = JSON.loads(res.content.decode('utf-8'))['result']['token'] #字节型的 response 转换成字符串型, 再转换成字典型
- print(token)
- return token
- if __name__ == '__main__':
- tc = get_tokenclass()
- # str_create()
- # signature_create()
- tc.token_creat()
- # tc.str_create()
- # tc.signature_create()
测试用例:
测试用例用 unittest 框架来组织
- """
- Created on 2019 年 04 月 03 日
- @author:
- """
- import requests
- import unittest
- import get_token
- from get_token import get_tokenclass
- import JSON
- import re
- import hashlib
- import random
- class Test(unittest.TestCase):
- def setUp(self):
- token_class = get_tokenclass()
- self.apiToken = token_class.token_creat()
- self.sign = token_class.signature_create()
- self.timeSTAP = get_token.time_stamp
- self.appKey = get_token.appKey
- self.appSecret = get_token.appSecret
- self.base_url = "http://10.10.10.100:8080"
- self.headers = {"Content-type": "application/json", "Connection": "close"}
- self.requestId = str(random.randint(0, 99999)) #每次请求 (每个 case) 生成不同的随机 requestId
- def tearDown(self):
- pass
- # 删除酒店
- def test_001(self):
- params = {
- "header": {
- "appKey": self.appKey,
- "apiToken": self.apiToken,
- "requestId": self.requestId,
- "timestamp": self.timeSTAP,
- "sign": self.sign
- },
- "body": {
- "hotels": [
- "aaa",
- "bbb"
- ]
- }
- }
- body_list1 = str(params["body"])
- body_list2 = body_list1.replace(body_list1[25:32], "udid")
- body_list3 = re.sub("[[]", "", body_list2)
- body_list = re.sub("[]]", "", body_list3)
- list_sig = self.timeSTAP + self.apiToken + self.appSecret + self.appKey + body_list
- signature = hashlib.sha1(list_sig.encode('utf-8')).hexdigest().upper().strip()
- params["header"]["sign"] = signature
- res = requests.post(url=self.base_url+"/partner/hotel/remove", data=JSON.dumps(params), headers=self.headers) #第二次签名验证
- response = JSON.loads(res.content.decode('utf-8'))
- self.assertEqual(response["msg"], "SUCCESS")
- if __name__ == '__main__':
- mySuit = unittest.TestSuite()
- tesTCases = ["test_001", "test_002", "test_003", "test_004", "test_005", "test_006", "test_007"]
- for cs in tesTCases:
- mySuit.addTest(Test(cs))
- # mySuit.addTest(Test("test_003"))
- myRun = unittest.TextTestRunner()
- myRun.run(mySuit)
另外, 学会了一个变量名 warning 的处理办法, pep8 编码规范, 要求变量名或者函数名最好包含大小写.
除了通过修改 pycharm 设置的方式, 还可以使用 "驼峰命名法" 来给变量或函数命名.
"驼峰命名法", 顾名思义, 就是变量或函数的命名要像骆驼的驼峰一样有高低起伏(Ps: 这个名字是不是很可爱呢~)
附上链接:
- -----------
- -----------
来源: https://www.cnblogs.com/ailiailan/p/10647120.html