python实现银联支付和支付宝支付接入
本文实例为大家分享了python银联支付和支付宝支付接入的具体代码,供大家参考,具体内容如下
前置条件:需要安装Python的OpenSSL模块,我使用的版本是16.1.0,可以使用pipinstallpyopenssl来安装
一、支付宝支付
1.使用RSA公钥加密系统进行签名和签名验证,需要自己生成一个RSA私钥和对应的一个RSA公钥(在Linux下可以使用ssh-keygen命令来生成),公钥需要上传至支付宝,供支付宝对开发者发送的请求做签名验证使用;而同时支付宝会提供一个RSA公钥给开发者,开发者使用这个公钥来验证支付宝的回调请求的合法性。
2.整个接入过程最核心的工作就是构建一个合法的请求报文,这个可以参考支付宝的相关文档;其次是对请求报文的内容进行RSA签名,并将签名随请求报文一并发送。
核心的签名和报文构建代码如下:
importOpenSSL importjson importtime importurllib importbase64 fromdjango.confimportsettings defbuild_sign(param_map,sign_type="RSA"): ''' Doc:https://doc.open.alipay.com/doc2/detail.htm?treeId=200&articleId=105351&docType=1 ''' #将筛选的参数按照第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值ASCII码递增排序,以此类推。 sort_param=sorted([(key,unicode(value,settings.ALIPAY_CHARSET).encode(settings.ALIPAY_CHARSET))forkey,valueinparam_map.iteritems()],key=lambdax:x[0]) #将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用&字符连接起来,此时生成的字符串为待签名字符串。SDK中已封装签名方法,开发者可直接调用,详见SDK说明。 #如自己开发,则需将待签名字符串和私钥放入SHA1RSA算法中得出签名(sign)的值。 content='&'.join(['='.join(x)forxinsort_param]) returnbase64.encodestring(OpenSSL.crypto.sign(settings.ALIPAY_APP_PRIVATE_KEY_OBJ,content,'sha1')) defbuild_params(out_trade_no,subject,body,total_amount): ''' Doc:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.MVkRGo&treeId=193&articleId=105465&docType=1 将参数按照支付宝规定组织并签名之后,返回 ''' params={} #获取配置文件 params['app_id']=settings.ALIPAY_APPID params['method']=settings.ALIPAY_METHOD params['format']=settings.ALIPAY_FORMAT params['charset']=settings.ALIPAY_CHARSET params['sign_type']=settings.ALIPAY_SIGN_TYPE params['sign_type']=settings.ALIPAY_SIGN_TYPE params['timestamp']=time.strftime('%Y-%m-%d%H:%M:%S') params['version']=settings.ALIPAY_VERSION params['notify_url']=settings.ALIPAY_NOTIFY_URL #业务参数 params['biz_content']={} params['biz_content']['body']=body#订单描述、订单详细、订单备注,显示在支付宝收银台里的“商品描述”里 params['biz_content']['subject']=subject#商品的标题/交易标题/订单标题/订单关键字等。 params['biz_content']['out_trade_no']=out_trade_no#商户网站唯一订单号 params['biz_content']['total_amount']='%.2f'%(float(total_amount)/100)#订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] params['biz_content']['product_code']=settings.ALIPAY_APP_PRODUCT_CODE params['biz_content']=json.dumps(params['biz_content'],separators=(',',':')) params['sign']=build_sign(params) returnurllib.urlencode(params) defcheck_sign(message,sign): '''Doc:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.dDRpeK&treeId=204&articleId=105301&docType=1''' try: OpenSSL.crypto.verify(settings.ALIPAY_PUBLIC_KEY_OBJ,sign,message,'SHA1') returnTrue exceptExceptionas_: returnFalse
在读取支付宝公钥的时候,由于OpenSSL模块使用的是X509格式的证书,所以需要做以下的处理(用于对发起支付报文进行签名):
#支付宝开发者公钥(支付宝生成) ALIPAY_PUBLIC_KEY=os.path.join(BASE_DIR,'utils/paycenter/alipay/certs/alipay_public_key') _ALIPAY_PUBLIC_KEY_OBJ_PUB=OpenSSL.crypto.load_publickey(OpenSSL.crypto.FILETYPE_PEM,open(ALIPAY_PUBLIC_KEY).read()) _ALIPAY_PUBLIC_KEY_OBJ_X509=OpenSSL.crypto.X509() _ALIPAY_PUBLIC_KEY_OBJ_X509.set_pubkey(_ALIPAY_PUBLIC_KEY_OBJ_PUB) ALIPAY_PUBLIC_KEY_OBJ=_ALIPAY_PUBLIC_KEY_OBJ_X509
载入开发者生成的私钥的代码为(用于验证支付宝回调请求的合法性):
#支付宝开发者应用私钥(接入方生成) ALIPAY_APP_PRIVATE_KEY=os.path.join(BASE_DIR,'utils/paycenter/alipay/certs/alipay_app_private_key') ALIPAY_APP_PRIVATE_KEY_OBJ=OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,open(ALIPAY_APP_PRIVATE_KEY).read(),None)
二、银联支付
1.银联支付(网关支付)与支付宝支付基本上遵循了同样的流程,但是在发起支付的请求报文和签名、验证签名等方面存在细微的差别,特别是在签名和验证签名时,支付宝是直接对报文内容进行了RSA加密,但是银联却是首先对签名内容取SHA1的摘要,继而对此摘要做RSA加密,这点在build_sign函数中就可以很明显地看出来。
2.银联支付的证书文件申请流程比较繁琐,并且其格式也和支付宝使用的不同,我们申请到的私钥证书文件是以PKCS12的格式保存的,并且需要注意在从指定位置下载此证书后,导出证书时一定要将密码设置为6位的整数数字,之后,还需要将PKCS12格式的证书文件上传至指定位置并启用才可以正常使用此证书。
核心的签名和报文构建代码如下:
importtime importhashlib importurllib,urllib2 importbase64 importOpenSSL fromdjango.confimportsettings defbuild_sign(param_map,sign_type="RSA"): '''构建签名''' #将筛选的参数按照第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值ASCII码递增排序,以此类推。 sort_param=sorted([(key,unicode(value,settings.UNIONPAY_ENCODING).encode(settings.UNIONPAY_ENCODING))forkey,valueinparam_map.iteritems()],key=lambdax:x[0]) content='&'.join(['='.join(x)forxinsort_param]) message=hashlib.sha1(content).hexdigest() returnbase64.b64encode(OpenSSL.crypto.sign(settings.UNIONPAY_PRIVATE_KEY_OBJ,message,'sha1')) defbuild_params(out_trade_no,total_amount): params={} #获取配置信息 params['accType']=settings.UNIONPAY_ACC_TYPE params['accessType']=settings.UNIONPAY_ACCESS_TYPE params['backUrl']=settings.UNIONPAY_BACK_URL params['frontUrl']=settings.UNIONPAY_FRONT_URL params['bizType']=settings.UNIONPAY_BIZ_TYPE params['certId']=settings.UNIONPAY_CERT_ID params['channelType']=settings.UNIONPAY_CHANNEL_TYPE params['currencyCode']=settings.UNIONPAY_CURRENCY_CODE params['encoding']=settings.UNIONPAY_ENCODING params['merId']=settings.UNIONPAY_MER_ID params['signMethod']=settings.UNIONPAY_SIGN_METHOD params['txnType']=settings.UNIONPAY_TXN_TYPE params['txnSubType']=settings.UNIONPAY_TXN_SUBTYPE params['version']=settings.UNIONPAY_VERSION params['orderId']=out_trade_no params['txnAmt']='%d'%int(total_amount)#单位为分 params['txnTime']=time.strftime('%Y%m%d%H%M%S')# params['signature']=build_sign(params) #returnparams returnurllib.urlencode(params) defcheck_sign(message,sign): try: OpenSSL.crypto.verify(settings.UNIONPAY_PUBLIC_KEY_OBJ,sign,message,'SHA1') returnTrue exceptExceptionas_: returnFalse
商户私钥证书的载入方法(用户对发起支付的报文进行签名):
#商户私钥证书 UNIONPAY_APP_PRIVATE_KEY_CERT=os.path.join(UNIONPAY_CERTS_PATH,UNIONPAY_APP_PRIVATE_KEY_CERT_FILENAME)#PKCS12format UNIONPAY_PRIVATE_KEYSTORE=OpenSSL.crypto.load_pkcs12(open(UNIONPAY_APP_PRIVATE_KEY_CERT).read(),UNIONPAY_APP_PRIVATE_KEY_CERT_PASSWORD) UNIONPAY_PRIVATE_KEY_OBJ=UNIONPAY_PRIVATE_KEYSTORE.get_privatekey()
银联公钥证书的载入方法(用于验证银联回调的合法性):
#银联公钥证书 UNIONPAY_PUBLIC_KEY_CERT=os.path.join(UNIONPAY_CERTS_PATH,UNIONPAY_PUBLIC_KEY_CERT_FILENAME) UNIONPAY_PUBLIC_KEY_OBJ=OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,open(UNIONPAY_PUBLIC_KEY_CERT).read())
后记:银联支付接入过程中,参考过其官方提供的一个Python实现的接口,里面同时使用了python的rsa模块和OpenSSL模块,并且对证书的格式做了各种处理,但是这些似乎是没有什么必要,只使用OpenSSL模块就完全可以完成相关的工作。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。