日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python支付_玩转京东支付(python)

發(fā)布時(shí)間:2023/12/10 python 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python支付_玩转京东支付(python) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

說明

做了微信。支付寶和京東支付之后,發(fā)現(xiàn),最扯蛋的支付,肯定是京東支付,要完整開發(fā)京東支付,必須要看完京東支付開發(fā)者文檔的官網(wǎng)每一個(gè)角落,絕對(duì)不能憑你的任何經(jīng)驗(yàn)去猜測(cè)有些流程,比如公私鑰加解密(不看官網(wǎng),保證你后悔)、發(fā)送請(qǐng)求的方式(form表單提交,看了官網(wǎng)你會(huì)發(fā)現(xiàn)好怪異),支付同步跳轉(zhuǎn)(還是post,fk),支付成功后返回居然沒有支付訂單號(hào)(完全靠自己去維護(hù),fk)

技術(shù)描點(diǎn)

首先要去看官網(wǎng)的:http://payapi.jd.com/。 項(xiàng)目使用的是pc網(wǎng)頁(yè)支付

一定要仔細(xì)的看這些參數(shù)的說明

特殊參數(shù)說明如下:

1) 在以上的請(qǐng)求參數(shù)中,商戶號(hào)是在注冊(cè)開通京東支付功能的時(shí)候,京東支付商戶管理系統(tǒng)為用戶分配的。

2) 用戶賬號(hào)是商戶系統(tǒng)的用戶賬號(hào)。

3) 交易流水號(hào)是用來標(biāo)識(shí)每次支付請(qǐng)求的號(hào)碼,需要商戶保證在每一次支付請(qǐng)求的時(shí)候交易流水號(hào)唯一,多次請(qǐng)求不能使用同一交易流水號(hào),否則京東支付服務(wù)在處理后面的支付請(qǐng)求時(shí),會(huì)把此交易當(dāng)做重復(fù)支付處理。

4) 簽名規(guī)則詳見:“接口安全規(guī)范-簽名算法”;

5) 為保證信息安全,表單中的各個(gè)字段除了merchant(商戶號(hào))、版本號(hào)(version)、簽名(sign)以外,其余字段全部采用3DES進(jìn)行加密。

二. 生成簽名

簽名過程分為兩步,首先是將原始參數(shù)按照規(guī)則拼接成一個(gè)字符串S1,然后再將S1根據(jù)簽名算法生成簽名字符串sign。

參數(shù)原始字符串的拼接規(guī)則:

1) 對(duì)于POST表單提交的參數(shù):所有參數(shù)按照參數(shù)名的ASCII碼順序從小到大排序(字典序),使用URL鍵值對(duì)的方式拼接成字符串S1,(如:k1=value1&k2=value2&k3=value3…)

2) 對(duì)于XML報(bào)文交互的參數(shù):將XML報(bào)文的各行去掉空格后直接拼接成一行字符串作為S1。如果報(bào)文只有一行則直接作為S1,不需要再進(jìn)行拼接。

生成簽名的過程如下:

1) 對(duì)拼接的參數(shù)字符串S1通過SHA256算法計(jì)算摘要,得到字符串S2;

2) 對(duì)字符串S2使用私鑰證書進(jìn)行加密,并進(jìn)行base64轉(zhuǎn)碼,得到簽名字符串sign; 接收方收到報(bào)文后先進(jìn)行base64解碼,再使用公鑰證書解密,然后驗(yàn)證簽名的合法性。

注意事項(xiàng):

1) 空參數(shù)不參與簽名;

2) 參數(shù)列表中的sign字段不參與簽名;

3) 為了簡(jiǎn)化處理,標(biāo)簽也參與簽名;

4) 參數(shù)區(qū)分大小寫;

5) RSA加密的規(guī)則為:由交易發(fā)起方進(jìn)行私鑰加密,接收方進(jìn)行公鑰解密;(可以使用RSA公私鑰校驗(yàn)工具來校驗(yàn)商戶RSA公私鑰是否匹配)

6) 系統(tǒng)會(huì)對(duì)商戶公鑰證書的有效性進(jìn)行校驗(yàn)。

簽名代碼:

def get_sign_str(params, is_compatible=False):

"""

生成簽名的字符串

Args:

params: 簽名的字典數(shù)據(jù)

is_compatible: 是否是兼容模式(對(duì)字典中value值為空的也簽名)

Returns:

返回簽名

"""

raw = [(k, params[k]) for k in sorted(params.keys())]

if is_compatible:

order_str = "&".join("=".join(kv) for kv in raw)

else:

order_str = "&".join("=".join(kv) for kv in raw if kv[1])

return order_str

def sign(self, prestr):

"""

生成簽名

Args:

prestr(str): 生成簽名的原字符串

Returns:

返回生成好的簽名

"""

key = MRSA.load_key(self.MERCHANT_RSA_PRI_KEY)

signature = key.private_encrypt(self.sha256(prestr), MRSA.pkcs1_padding)

sign = base64.b64encode(signature)

return sign

三. DES3對(duì)每個(gè)參數(shù)進(jìn)行加密(merchant(商戶號(hào))、版本號(hào)(version)、簽名(sign)除外)

為防止明文數(shù)據(jù)在post表單提交的時(shí)候暴露,所以京東做了DES3對(duì)字段進(jìn)行加密(不用表單提交不就行了,還搞這么復(fù)雜,真該學(xué)學(xué)支付寶和微信)

京東DES加密說明如下:

除特定說明外,商戶和京東支付接口調(diào)用報(bào)文采用3DES加密,再通過base64轉(zhuǎn)換為字符串。

3DES加密算法標(biāo)為DESede,工作模式為電子密碼本模式ECB,不填充(DESede/ECB/NoPadding)。

注:服務(wù)端NoPadding 為不填充,所以加密的原文字節(jié)必須是8的整數(shù)倍(如果調(diào)用我們提供的加密接口API則不必處理原文字節(jié),加密接口內(nèi)部已處理)。如果自己實(shí)現(xiàn)加密,原文字節(jié)不夠8的整數(shù)倍,則按如下規(guī)則轉(zhuǎn)為8的整數(shù)倍。

1. 把原文字符串轉(zhuǎn)成字節(jié)數(shù)組。

2. 根據(jù)字節(jié)數(shù)組長(zhǎng)度判斷是否需要補(bǔ)位。

補(bǔ)位邏輯為:

int x = (i+ 4) % 8;

int y = (x == 0) ? 0 : (8 - x);

i為字節(jié)數(shù)組的長(zhǎng)度,y為需要補(bǔ)位的長(zhǎng)度。

補(bǔ)位值為0。

3. 將有效數(shù)據(jù)長(zhǎng)度byte[]添加到原始byte數(shù)組的頭部。

i為字節(jié)數(shù)組的長(zhǎng)度。

result[0] = (byte) ((i >> 24) & 0xFF);

result[1] = (byte) ((i >> 16) & 0xFF);

result[2] = (byte) ((i >> 8) & 0xFF);

result[3] = (byte) (i & 0xFF);

4. 原文字節(jié)數(shù)組前面加上第三步的4個(gè)字節(jié),再加上需補(bǔ)位的值。

例如:字符串”1”,轉(zhuǎn)換成字節(jié)數(shù)組是[49],計(jì)算補(bǔ)位y=3, 計(jì)算有效數(shù)據(jù)長(zhǎng)度為[0, 0, 0, 1],最后字節(jié)數(shù)組為[0, 0, 0, 1, 49, 0, 0, 0]。

Form表單接口的加密方式:

如果商戶通過表單方式提交支付請(qǐng)求至收銀臺(tái),為保證信息安全,表單中的各個(gè)字段除了merchant(商戶號(hào))、verion(版本號(hào))、sign(簽名)以外,其余字段全部采用3DES進(jìn)行加密。

XML請(qǐng)求接口的加密方式:

通過XML接口方式和京東支付服務(wù)器交互的請(qǐng)求,應(yīng)該對(duì)報(bào)文進(jìn)行加密,加密方式為對(duì)整個(gè)報(bào)文整體進(jìn)行3DES加密,再進(jìn)行base64轉(zhuǎn)碼使其變?yōu)榭勺x字符串,加密后的密文置于標(biāo)簽中,同時(shí)再將報(bào)文中的(商戶號(hào))、(版本號(hào))這兩個(gè)字段單獨(dú)置于標(biāo)簽下。

接收到京東支付加密報(bào)文后的處理方式:

接收到京東支付返回的加密報(bào)文后,先判斷標(biāo)簽下的標(biāo)簽的返回碼,檢查接口調(diào)用是否正常返回。然后再讀取標(biāo)簽的密文內(nèi)容進(jìn)行base64解碼,再進(jìn)行3DES解密,解密后的報(bào)文即是原始報(bào)文。

示例代碼:

def des_pad(data):

e = len(data)

x = (e + 4) % 8

y = 0 if x == 0 else 8 - x

sizeByte = struct.pack('>I', e)

resultByte = range(len(sizeByte) + e + y)

resultByte[0:4] = sizeByte

resultByte[4:4 + e] = data

for i in range(0, y):

resultByte[e + 4 + i] = "\x00"

resultstr = ''.join(resultByte)

return resultstr

def encode_des(to_encode_str, des_key):

"""

DES3加密數(shù)據(jù)

Args:

to_encode_str(str): 要被加密的原字符串,這里的字符串需要被des_pad一下

des_key(str): 加密的key

Returns:

"""

key = base64.b64decode(des_key)

des3 = DES3.new(key, DES3.MODE_ECB)

return des3.encrypt(ToolsClass.des_pad(to_encode_str)).encode('hex_codec')

這樣的話,簽名和加密都已完成,往后就拼到頁(yè)面里的form里

/>

/>

/>

/>

怎么組織就自己去實(shí)現(xiàn)好了

四. 異步回調(diào)

提交之后請(qǐng)求之后,就會(huì)跳轉(zhuǎn)到京東的支付頁(yè)面,可登錄賬戶支付,也可用京東app或者微信掃描支付。

當(dāng)用戶掃碼支付之后,京東會(huì)主動(dòng)跳轉(zhuǎn)到你指定的一個(gè)網(wǎng)址(在提交支付請(qǐng)求的時(shí)候有這個(gè)字段),并且會(huì)異步post一個(gè)請(qǐng)求到指定的一個(gè)地址(在提交支付請(qǐng)求的時(shí)候有這個(gè)字段),同步跳轉(zhuǎn)是在用戶掃碼支付之后,如果京東支付頁(yè)面還在的話會(huì)跳轉(zhuǎn)。而異步是無論如何都會(huì)發(fā)支付結(jié)果通知的。對(duì)于新手來說,一定要知道這個(gè)行業(yè)潛規(guī)則(微信,支付寶or其它都是)。而且一定要以這個(gè)異步通知的結(jié)果為準(zhǔn)。

京東返回的是xml格式的字符串

返回格式如下(沒有換行的,我這里演示換了行的):

V2.0

22294531

000000 success

MWYxMjBjMzViZjgwOWM5ZDhjNjc0YmY1ZWJlY2QyODU0YTc5NmQ3ZWQxMWU1NzE3MWQ0OTUwOGI5NzllYmE4ZjM1YzRiZjlmYWE1M2ZiYjVmYzBmYTgyMDYyM2Q0YjM0NGM1ODFkZDhlYTA2Mjk0ZDE5ZDBlZDk5NTc3MmE4Nzk4OTFlYjIwZDgzMTc4MDU3NGVkZTFjNDY0MDMzNzNjZjc2OWZiMDQ0YjVhZGNhYmRhMGZmYTkyNzRhZDNhM2IxOGY5ZjZhYjBmYjhmZmI3Yzg0OTA3YzM0OGJmZTYwZTIzNzM3YjVmYzMzNmNkYTE0MjM2OWIwZDM5MjI2YWM5YmY3ZmZjZDBkNWJmM2ZkYWY4YTU3OWU4MDE3ZjQ5YmQ0ZWIyMDA0NTFmODZkNmViMDBiMDE2YTU3NTNjMzJjNDIzNWI5ZDkyYzQ3OTU4OTc2ZGIyZmNiMGUxNGRjNTM2OGZjYjQ0NmE0YWY1ZWVjZDYzNWI5ZDkyYzQ3OTU4OTc2NmIwM2QyZTU1ODJlNDNjM2M1NjA2YmQ5ZDc3MTRkMmNjN2ZiMDM3Yzg5ZDk1ODFkMWJhZmVjYjUwMzJlNTdkMTFmN2QxMDAxNjgyMzJjNTZhMmQzNTcyZGE4OTUzYWFjNTU5MDY4YWYyODE5ZDcyNmY5NmE1YTBmYWFiZTRiZTQ2OGZhMmM4M2JjMGM5NmNiMDE3ZWQ4MDkxY2FjZThiNzg4MjY5OWY1ZTJlYzBjOTIxODBhOGExNjExNGY4NWQwM2NkZjI2MTFmM2VmODcxYWM3MjUxZjMxMzZlYjFmNzI1NWE0OWM4MjMxZGY1MzBmY2Y1Mjg2NGUzMWRlMjc0M2I5ZDM5NjQzN2ZmZWQ1Y2M5NDY4ZDcwNWM1YzVhZmRlYzYwZWU3MDVhNjE0N2I1MGVlM2UyMGE2MzExNTE4YTUxOGRjMzBmMmUxZjE2NzYzNGRiNDJlODFmMDczOGYzZjMxN2NkMjkzNmU4ODc3NzJjMjkzM2ZlODlmMjUyNDVmNDI2MDA0M2VkYmUwOTlkNGEyNjU3YTM5YTE4ODU2OTBmNGQyNDcwZDE0ZWRjMmQxYjgxMzhhNjA5M2ZlNDkxYTQyMzE5YzBlNTA0MTdkYTg2ZGQ2NDQwODBmMjM4ZGI2YzIzMjNhOTE0M2VmMjZiZjczN2M5NWQwODYxMWY2OGE5MDQ0ZDZmNzE0NmIxZjQwZDdmZDMxOTQ2ZDM3YjIwNDJiODUzZGM0NTk0MzM5YzJkN2M2NDdiNGM4MzQ4MTRjZTIxZTlmYTYzNDYxNGMxMjlhZTE3NjE0ZDIzM2Q2MTQ4YzJiNWE3ZWVjMDU5MjFmNzJkNGNjNTU1NWZkNzVhN2U5Y2I1MDU1NjhlMWRlNjVhNzkyOGUxMThlODQyMGJkNzE2NjdmMDc3YmEyYTFkNmQyOTFiOGNjZTU2ZGMyYmE3ODY5ZGZiNmMyMWViYjc2ODc0Y2I3YTc4NGQ5NWY2NjY2Y2E5NjI0N2I1MGE4MTliMDBkNGIzNmViZTJlY2JmYTcwODUzYTM5ZTcwMDVmYWEzNWY2MDFhMWM2MGQ1MzEyYmQxNDU3Zjg4ZWVhNzY2YjZhOGE4ZGMxMGY3NjYwOWEzNWY2MDFhMWM2MGQ1MzFhNzA4NTNhMzllNzAwNWZhYTYxMmJmNjJiMmFlMGY5ODMxMzQ0MzQ0NjMxZDc3MTUyY2FiMjZlMjcyYmJjYmQzODVmNDY4OTA5YTdjMjlmNTI5NWFlZjE3NTI4ZmE4MzVhNzA4NTNhMzllNzAwNWZhNDk5OTQ2ZGU0OGU0NGQ2ZTE4YmRiYTBjZjNhM2ZkNjY5ODJjNGVhZjQzMjIyYWFhMWM0ZmU1ODRiNTg5OWEwYzAwNjI2NTllMDZkYzhiYTVmMjI3ZjUyYmQ3MjcyODllZmEwYzhiNDIwODc4ZjUzODY1MzAzZDkyNDM5OTRkNDczMTBjZDBhMTc4ZjAwOTIyZmM2ODk5YjkyYTJiODcwNjU4MzkzMzJkZWYzNDY1MzJlYTNiYTFhNjM0MWIwNjM4NjBjNjlmMzg1NWZjZWM5YWExMDdjZWY1MjkwZTZjMzgzOGYxNTRiNzFlN2E1YTczYWFkNzJlOTRiOWI3MmI2YWYyMTJjMjQ5Y2UzMmUxMGI4YWE0N2YzYzFmNjNiOGY4NjJlZmU1ZDM5NjcwODA3MGNjY2JjYWFkYjM3NzBmMGQzYjIyMGFmZTE3YWNjZWU1N2RmZTQxMzAxYjA2MDdlMg==

先要用DES3對(duì)encrypt節(jié)點(diǎn)里的串進(jìn)行解密

def un_des_pad(data):

resultByte = data[0:4]

e = struct.unpack('>I', resultByte)[0]

x = (e + 4) % 8

y = 0 if x == 0 else 8 - x

return data[4:] if y == 0 else data[4:-y]

def decode_des(to_decode_str, des_key):

"""

解密數(shù)據(jù)

Args:

to_decode_str(str): 要解密的原字符串

des_key(str): 解密的key

Returns:

"""

key = base64.b64decode(des_key)

des3 = DES3.new(key, DES3.MODE_ECB)

param = to_decode_str.decode("hex_codec") if to_decode_str is bytes else base64.b64decode(to_decode_str).decode(

"hex_codec")

param = des3.decrypt(param)

return ToolsClass.un_des_pad(param)

sign_begin = xml_data.find('')

sign_end = xml_data.find('')

encrypt_str = xml_data[sign_begin + 9:sign_end]

xml_str = JdPay.decode_des(encrypt_str, deskey)

解密后的明文如下:

V2.0

110290193003

000000

success

6220

SJ6qfS+9CmXkt6ghJcf9nIdHJDReTFNkRyjFh5XZAsTAtfHT4SdmKeD88t+2dMnaszJ7vVjBnSu64aJyt6SODW2FHJk0WXEvZNixmo2h8F7vHO5lTE2jEG/9uN7sqg2c7kH2Fnu5cFLCeaMfb8uZqZ8CKi+g7Aw4b6rywvoH/8M=

201704250935156041484635

0

3140

2

3

1500

CNY

20170425093516

1

1640

CNY

20170425093516

150****1596

解密之后就是驗(yàn)證簽名是否正確,從上邊的串中拿到簽名和去除簽名之后的字符串

def verify_mysign(cls, sign, xml_str, jd_public_key):

"""

驗(yàn)證簽名

Args:

sign: 簽名

xml_str: 去除簽名后的xml字符串

jd_public_key: 用于驗(yàn)證的key

Returns:

"""

xml_sha_str = SHA256.new(xml_str).hexdigest()

key = MRSA.load_pub_key(jd_public_key)

signature = key.public_decrypt(base64.standard_b64decode(sign),

MRSA.pkcs1_padding)

return signature == xml_sha_str

驗(yàn)證通過之后再返回去除sign的xml字符串,并提取出里邊的內(nèi)容(詳情參數(shù)所代表的含義請(qǐng)看官方文檔)

五. 同步跳轉(zhuǎn)

同步跳轉(zhuǎn)就沒啥好說了,只是給個(gè)跳轉(zhuǎn)地址,但是這里一定要注意,這個(gè)的是一個(gè)post請(qǐng)求(好像京東啥都喜歡post),而非微信或者支付寶或者other什么的get請(qǐng)求。所以不要設(shè)置錯(cuò)了

好了,到這里一個(gè)完整的在線支付就完成了。這里還要說明的是,涉及到加密和解密,就一定會(huì)有key,有DES3使用的對(duì)稱加密key,還有簽名使用的非對(duì)稱公鑰和私鑰。所以一定要配置好。

這里我的源代碼里用的都是京東提供的測(cè)試商戶號(hào),還有一大推京東設(shè)置好的key,具體要去下載京東的【京東支付PC&H5接口文檔】,在文檔的最底部有帳號(hào)信息。

demo里邊還有申請(qǐng)退款,申請(qǐng)撤單的接口,其實(shí)寫好一個(gè)接口的完成流程,別的流程都是直接套用就可以了。

總結(jié)

以上是生活随笔為你收集整理的python支付_玩转京东支付(python)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。