from datetime importdatetimefrom Crypto.PublicKey importRSAfrom Crypto.Signature importPKCS1_v1_5from Crypto.Hash importSHA256from urllib.parse importquote_plusfrom urllib.parse importurlparse, parse_qsfrom base64 importdecodebytes, encodebytesimportjsonclassAliPay(object):"""支付宝支付接口(PC端支付接口)"""
def __init__(self, appid, app_notify_url, app_private_key_path,
alipay_public_key_path, return_url, debug=False):
self.appid=appid
self.app_notify_url=app_notify_url
self.app_private_key_path=app_private_key_path
self.app_private_key=None
self.return_url=return_url
with open(self.app_private_key_path) as fp:
self.app_private_key=RSA.importKey(fp.read())
self.alipay_public_key_path=alipay_public_key_path
with open(self.alipay_public_key_path) as fp:
self.alipay_public_key=RSA.importKey(fp.read())#注意如果debug如果不是True将不是沙箱环境【标识非正式环境url中含有dev字样】
if debug isTrue:
self.__gateway = "https://openapi.alipaydev.com/gateway.do"
else:
self.__gateway = "https://openapi.alipay.com/gateway.do"
def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
biz_content={"subject": subject,"out_trade_no": out_trade_no,"total_amount": total_amount,"product_code": "FAST_INSTANT_TRADE_PAY",#"qr_pay_mode":4
}
biz_content.update(kwargs)
data= self.build_body("alipay.trade.page.pay", biz_content, self.return_url)returnself.sign_data(data)def build_body(self, method, biz_content, return_url=None):
data={"app_id": self.appid,"method": method,"charset": "utf-8","sign_type": "RSA2","timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),"version": "1.0","biz_content": biz_content
}if return_url is notNone:
data["notify_url"] =self.app_notify_url
data["return_url"] =self.return_urlreturndatadefsign_data(self, data):
data.pop("sign", None)#排序后的字符串
unsigned_items =self.ordered_data(data)
unsigned_string= "&".join("{0}={1}".format(k, v) for k, v inunsigned_items)
sign= self.sign(unsigned_string.encode("utf-8"))#ordered_items = self.ordered_data(data)
quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v inunsigned_items)#获得最终的订单信息字符串
signed_string = quoted_string + "&sign=" +quote_plus(sign)returnsigned_stringdefordered_data(self, data):
complex_keys=[]for key, value indata.items():ifisinstance(value, dict):
complex_keys.append(key)#将字典类型的数据dump出来
for key incomplex_keys:
data[key]= json.dumps(data[key], separators=(',', ':'))return sorted([(k, v) for k, v indata.items()])defsign(self, unsigned_string):#开始计算签名
key =self.app_private_key
signer=PKCS1_v1_5.new(key)
signature=signer.sign(SHA256.new(unsigned_string))#base64 编码,转换为unicode表示并移除回车
sign = encodebytes(signature).decode("utf8").replace("\n", "")returnsigndef_verify(self, raw_content, signature):#开始计算签名
key =self.alipay_public_key
signer=PKCS1_v1_5.new(key)
digest=SHA256.new()
digest.update(raw_content.encode("utf8"))if signer.verify(digest, decodebytes(signature.encode("utf8"))):returnTruereturnFalsedefverify(self, data, signature):if "sign_type" indata:
sign_type= data.pop("sign_type")#排序后的字符串
unsigned_items =self.ordered_data(data)
message= "&".join(u"{}={}".format(k, v) for k, v inunsigned_items)return self._verify(message, signature)