python介面自動化-實現sign簽名(MD5加密)
本文內容皆為作者原創,碼字不易,如需轉載,請註明出處:https://www.cnblogs.com/temari/p/13513636.html
一,前序
今天在學習sign簽名的的時候,瞭解了下常用的sign加密演算法,突然心血來潮,想用python試著將簽名生成的通用步驟用程式碼實現出來,雖然中間經歷了一點小波折,請教了開發同事後,按照他給的思路建議,搞定了。我實現的是微信支付的簽名演算法規則。
二,加密業務規則
簽名生成的通用步驟如下:第一步,設所有傳送或者接收到的資料為集合M,將集合M內非空引數值的引數按照引數名ASCII碼從小到大排序(字典序),使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字串stringA。
特別注意以下重要規則:
1.引數名ASCII碼從小到大排序(字典序);
2.如果引數的值為空不參與簽名;
3.引數名區分大小寫;
4.驗證呼叫返回或微信主動通知簽名時,傳送的sign引數不參與簽名,將生成的簽名與該sign值作校驗。
5.微信介面可能增加欄位,驗證簽名時必須支援增加的擴充套件欄位。
第二步,在stringA最後拼接上key得到stringSignTemp字串,並對stringSignTemp進行MD5運算,再將得到的字串所有字元轉換為大寫,得到sign值signValue。
參考網址:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
三,程式碼設計
3.1 引數型別確定
由微信支付簽名生成規則描述可知,需要加密的引數資料是按照鍵值對的形式拼接,且引數名區分大小寫,將引數資料定義為字典Dict型別特別合適,由於python本身區分大小寫,字典鍵值也區分大小寫。#如程式碼所示:
>>> data={'q':'apple','Q':'orange'}
>>> data['q']
'apple'
>>> data['Q']
'orange'
3.2 引數設計
為了滿足"引數的值為空不參與簽名,傳送的sign引數不參與簽名,介面引數支援擴充套件”的簽名演算法規則,引數字典data在設計的時候除了要包含微信支付介面提供的必傳引數外,另外我補充了引數值為空和引數名為sign的引數,如下:
#string1,string2使用者擴充套件,增加引數名sign的引數
data={
'appid':'wxd930ea5d5a258f4f',
'mch_id':'10000100',
'device_info':'1000',
'body':'test',
'nonce_str':'ibuaiVcKdpRxkhJA',
'string1':'',
'string2':'',
'sign':'fdsfdhgjghjf'
}
3.3 自定義函式設計
引數data確定下來後,由於存在引數名為sign或者引數值為空的引數,這兩種引數是不參與簽名的。需要寫一個函式,用於排除引數名為sign或者引數值為空的引數。另外參與簽名的引數生成後,引數名要按照ASCII進行從小到大排序,然後跟引數值進行拼接,這裡需要設計一個拼接函式。拼接函式需要實現引數名排序,python資料型別中,字典沒有排序功能,但是列表有一個sort()函式可實現物件排序,因此要把字典的鍵值單獨取出來存放到列表中進行排序,排序完成後再根據鍵名取字典對應的鍵值。
3.4 加密函式
需要加密的字串生成後,可以利用python的hashlib模組對字串進行加密。Python的hashlib提供了常見的摘要演算法,如MD5,SHA1等等,這裡我用md5加密。加密後把字串轉換成大寫,生成sign簽名。
3.5 簽名實現邏輯
1.將傳的引數定義成字典型別資料A。
2.排除引數名為sign或者引數值為空的引數,另存為新的字典型別資料B。
3.將引數名用ASCII進行從小到大排序,引數名儲存成列表物件。
4.用排序完成的引數名迴圈遍歷字典資料B,跟引數值拼接。引數名1=引數值&引數名2=引數值&...
5.引數拼接完成,每個商戶的key值也需要拼接,生成拼接API祕鑰。
6.拼接完成的字串,MD5加密,使用hashlib模組。
7.將加密得到的字串所有字元轉換為大寫,得到sign值signValue。
四,程式碼實現
完整程式碼如下:
"""
介面名稱:微信支付
實現目標:微信支付sign簽名MD5加密
簽名演算法規則:
1.引數名ASCII碼從小到大排序(字典序)
2.如果引數的值為空不參與簽名
3.引數名區分大小寫
4.驗證呼叫返回或微信主動通知簽名時,傳送的sign引數不參與簽名,將生成的簽名與該sign值作校驗
5.微信介面可能增加欄位,驗證簽名時必須支援增加的擴充套件欄位
"""
#匯入資料處理加密的包
import hashlib
keyString="192006250b4c09247ec02edce69f6a2d"
#所有傳送或者接收到的資料定義為字典型別資料
data={
'appid':'wxd930ea5d5a258f4f',
'mch_id':'10000100',
'device_info':'1000',
'body':'test',
'nonce_str':'ibuaiVcKdpRxkhJA',
'string1':'',
'string2':'',
'sign':'fdsfdhgjghjf'
}
#定義函式作用:去除引數的值為空或者引數名為sign的資料,返回參與簽名的字典型別資料
def GetSignData(data):
signData={}
for key, value in data.items():
if value != "" and key != "sign":
signData[key] = value
return signData
#對引數按照key=value的格式,並按照引數名ASCII字典序排序拼接成字串stringA,最後拼接上key,返回拼接API金鑰。
def SignString(signData,key):
#定義空列表
list=[]
# 定義空字串
stringA=""
#迴圈遍歷字典資料的鍵值,取出存放到列表中
for key in signData.keys():
list.append(key)
#對列表的物件進行排序,預設升序,即按照ASCII碼從小到大排序
list.sort()
#迴圈遍歷排序後的列表,根據鍵值取出字典鍵對應的值
for i in list:
stringA += i+"="+signData[i]+"&"
#引數拼接成需要加密的字串
stringA += "key"+"="+keyString
return stringA
#呼叫GetSignData函式,獲取參與簽名的引數,返回新的字典資料
signData=GetSignData(data)
#呼叫函式,返回需要加密的字串
signBody=SignString(signData,keyString)
print(signBody)
#建立物件md
md=hashlib.md5()
#對stringA字串進行編碼
md.update(signBody.encode('utf-8'))
#資料加密
signValue=md.hexdigest()
#把加密的結果,小寫轉換成大寫,upper函式
signValue=signValue.upper()
print(signValue)
程式碼演示:
用python程式碼編寫生成的sign簽名與微信支付網頁的簽名一樣,說明程式碼正確,如圖: