一、背景
最近負責的項目接口簽名規則做了調整,第一次接觸“2次認證“的方式,正好有時間,記錄一下。
測試的服務A有一部分接口需要給第三方調用,這樣需要對第三方有個認證,認證是由一個公共服務(API鑒權服務)來完成的。
基本框架:
調用時序圖:
第三方調用服務A的認證流程:
1、先訪問API鑒權服務來獲取apiToken(即拿到訪問服務A的認證)
2、再由獲取到的apiToken參與服務A的簽名認證規則
這樣就相當於在第三方和服務A直接增加了2次認證,安全性有了更好的保障。
流程1(獲取apiToken)的簽名規則如下:
1、將所有請求參數的值放入List中,注意:計算sign時所有參數不應進行URLEncode; 2、將格式化后的參數以字典序升序排列,拼接在一起,注意字典序中大寫字母在前,空值(null)使用空字符串代替; 3、將B形成字符串獲取SHA1摘要,形成一個40位的十六進制(字母大寫)字符串,即為本次請求signature(簽名)的值;
流程2(獲取服務A的簽名)的規則如下:
1、參與簽名的參數為:apiToken+appKey+appSecret+timestamp+body(提取body中的所有參數) 2、將格式化后的參數以字典序升序排列,拼接在一起 3、將第二步形成字符串獲取SHA1摘要 4、第三步獲得的字符串即為簽名參數
二、代碼實現
規則同時也是簽名的構造方法,按照上面所列的步驟用Python來實現。
獲取apiToken:
請求參數有3個:
appKey:應用KEY(必填項)
timestamp: 訪問時間戳(必填項),Unix時間戳;
signature:簽名(必填項)
1 """
2 Created on 2019年04月03日 3 @author: 4 """
5
6 import time 7 import hashlib 8 import requests 9 import operator 10 import json 11
12 appKey = "n3nuk67byade3c3qgrccjhosvmqfzt7z5wavp3ig"
13
14 appSecret = "b3a3056ef7ffb441332892ed76998b2e"
15
16 time_stamp = str(int(time.time())) 17
18 url = "http://10.10.10.100:8080/rest/v1/token/get"
19
20
21 class get_tokenclass(): 22
23 # 生成字符串
24 def str_create(self): 25 if operator.lt(appKey[0], appSecret[0]) == bool(1): #py3中operator類和py2中cmp()函數的作用相似,通過比較2個值的大小,返回布爾類型
26 strnew = time_stamp + appKey + appSecret 27 else: 28 strnew = time_stamp + appSecret + appKey 29 print(strnew) 30 return strnew 31
32
33 # 生成signature
34 def signature_create(self): 35 str_switch = self.str_create() 36 signature = hashlib.sha1(str_switch.encode('utf-8')).hexdigest().upper().strip() 37 print(signature) 38 return signature 39
40
41 # 生成token
42 def token_creat(self): 43 signature = self.signature_create() 44 params = {"appKey":appKey, "timestamp":time_stamp, "signature":signature} 45 res = requests.get(url=url,params=params) 46 print(res.url) 47 print(json.loads(res.content.decode('utf-8'))) 48 token = json.loads(res.content.decode('utf-8'))['result']['token'] #字節型的response轉換成字符串型,再轉換成字典型
49 print(token) 50 return token 51
52
53 if __name__ == '__main__': 54 tc = get_tokenclass() 55 # str_create()
56 # signature_create()
57 tc.token_creat() 58 # tc.str_create()
59 # tc.signature_create()
測試用例:
測試用例用unittest框架來組織
1 """
2 Created on 2019年04月03日 3 @author: 4 """
5
6 import requests 7 import unittest 8 import get_token 9 from get_token import get_tokenclass 10 import json 11 import re 12 import hashlib 13 import random 14
15
16 class Test(unittest.TestCase): 17
18 def setUp(self): 19 token_class = get_tokenclass() 20 self.apiToken = token_class.token_creat() 21 self.sign = token_class.signature_create() 22 self.timeSTAP = get_token.time_stamp 23 self.appKey = get_token.appKey 24 self.appSecret = get_token.appSecret 25 self.base_url = "http://10.10.10.100:8080"
26 self.headers = {"Content-type": "application/json", "Connection": "close"} 27 self.requestId = str(random.randint(0, 99999)) #每次請求(每個case)生成不同的隨機requestId
28
29
30 def tearDown(self): 31 pass
32
33
34 # 刪除酒店
35 def test_001(self): 36 params = { 37 "header": { 38 "appKey": self.appKey, 39 "apiToken": self.apiToken, 40 "requestId": self.requestId, 41 "timestamp": self.timeSTAP, 42 "sign": self.sign 43 }, 44 "body": { 45 "hotels": [ 46 "aaa", 47 "bbb"
48 ] 49 } 50 } 51 body_list1 = str(params["body"]) 52 body_list2 = body_list1.replace(body_list1[25:32], "udid") 53 body_list3 = re.sub("[[]", "", body_list2) 54 body_list = re.sub("[]]", "", body_list3) 55 list_sig = self.timeSTAP + self.apiToken + self.appSecret + self.appKey + body_list 56 signature = hashlib.sha1(list_sig.encode('utf-8')).hexdigest().upper().strip() 57 params["header"]["sign"] = signature 58 res = requests.post(url=self.base_url+"/partner/hotel/remove", data=json.dumps(params), headers=self.headers) #第二次簽名驗證
59 response = json.loads(res.content.decode('utf-8')) 60 self.assertEqual(response["msg"], "SUCCESS") 61
62
63 if __name__ == '__main__': 64 mySuit = unittest.TestSuite() 65 tesTCases = ["test_001", "test_002", "test_003", "test_004", "test_005", "test_006", "test_007"] 66 for cs in tesTCases: 67 mySuit.addTest(Test(cs)) 68 # mySuit.addTest(Test("test_003"))
69 myRun = unittest.TextTestRunner() 70 myRun.run(mySuit)
另外,學會了一個變量名warning的處理辦法,pep8編碼規范,要求變量名或者函數名最好包含大小寫。
除了通過修改pycharm設置的方式,還可以使用“駝峰命名法”來給變量或函數命名。
“駝峰命名法”,顧名思義,就是變量或函數的命名要像駱駝的駝峰一樣有高低起伏(Ps:這個名字是不是很可愛呢~)
附鏈接:
-----------
-----------
另外:python的hashlib庫還可以完成密碼的md5加密等功能。
如:
import hashlib password1 = hashlib.md5("123456".encode('utf-8')).hexdigest().upper().strip() print(password1)
結果:E10ADC3949BA59ABBE56E057F20F883E
不錯的文章:
-----------
https://blog.csdn.net/m0_38080253/article/details/78838489
https://blog.csdn.net/qq_24452475/article/details/79623051
-----------