簡(jiǎn)單-微信支付寶支付

自己總結(jié)的微信支付寶支付流程和注意點(diǎn):

準(zhǔn)備工作:

需要公司的營(yíng)業(yè)執(zhí)照,稅務(wù)信息,等老板的身份證信息等,我記得,用這些材料,去支付寶注冊(cè)一個(gè)商家賬戶(hù)(審核周期大概5個(gè)工作日),或者微信的開(kāi)發(fā)者賬號(hào)(審核周期大概5個(gè)工作日,300元費(fèi)用),微信的話(huà),需要你的app已經(jīng)上架有了APPID,才能開(kāi)通;大概也是5個(gè)工作日

用微信支付時(shí):用戶(hù)點(diǎn)擊支付按鈕時(shí)要先判斷有沒(méi)有安裝微信,以及當(dāng)前的微信版本是否支持支付,都滿(mǎn)足則進(jìn)入到微信界面,調(diào)起微信支付,在進(jìn)行微信支付的

支付文檔鏈接:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1

支付寶支付分為:支付寶有“移動(dòng)快捷支付”(支付時(shí)跳轉(zhuǎn)到支付寶APP,需要用戶(hù)安裝支付寶APP),或者“移動(dòng)WAP網(wǎng)頁(yè)支付”(支付時(shí)打開(kāi)一個(gè)WebView里邊登陸支付寶進(jìn)行支付)我看到大部分app美團(tuán)大眾點(diǎn)評(píng)支付寶支付都是第二種

支付寶支付步驟:

1.先與支付寶簽約,獲得商戶(hù)ID(partner)和賬號(hào)ID(seller)

2.下載相應(yīng)的公鑰私鑰文件(用來(lái)加密簽名)

3.下載支付寶SDK

4.生產(chǎn)訂單信息(客戶(hù)端或放在服務(wù)端生成訂單號(hào),支付寶支付成功后會(huì)通知服務(wù)端,這樣在服務(wù)端生成訂單的話(huà),可以掌握所有的訂單,而且還會(huì)更加安全)

5.調(diào)用支付寶支付接口發(fā)送訂單,由支付寶客戶(hù)端跟支付寶安全服務(wù)器打交道

6.支付完畢后返回支付結(jié)果給商戶(hù)客戶(hù)端,進(jìn)行結(jié)構(gòu)處理

安全問(wèn)題:接收到的支付結(jié)果可能被截獲修改。所以,就需要在生成訂單和處理支付結(jié)果時(shí)做安全性校驗(yàn)

生成訂單時(shí)對(duì)數(shù)據(jù)簽名,收到支付結(jié)果時(shí)對(duì)數(shù)據(jù)進(jìn)行簽名驗(yàn)證,以檢驗(yàn)數(shù)據(jù)是否被篡改過(guò)。

支付寶目前只支持采用RSA加密方式做簽名驗(yàn)證。

RSA加密算法除了可加解密外,還可用來(lái)作簽名校驗(yàn)。

簡(jiǎn)單的說(shuō),RSA會(huì)生成一個(gè)私鑰和一個(gè)公鑰,私鑰你應(yīng)該獨(dú)自保管,公鑰你可以分發(fā)出去。

做簽名驗(yàn)證時(shí),你可以用私鑰對(duì)需要傳輸?shù)臄?shù)據(jù)做簽名加密,生成一個(gè)簽名值,之后分發(fā)數(shù)據(jù),接收方通過(guò)公鑰對(duì)簽名值做校驗(yàn),如果一致則認(rèn)為數(shù)據(jù)無(wú)篡改

具體到支付寶使用RSA做簽名驗(yàn)證,就是在生產(chǎn)訂單時(shí),需要使用私鑰生成簽名值;在處理返回的支付結(jié)果時(shí),需要使用公鑰驗(yàn)證返回結(jié)果是否被篡改了。

實(shí)例代碼:

@WeakObj(self);

NDHttpRequestManage*request = [NDHttpRequestManagerequestManage];

//需要傳給支付寶的AppScheme

NSString*appScheme =@"aaa2015080600202133";

[requestuserObtainAliSign:[self.user.userIDndValue]

AndTradeNo:_tradeNo

complete:^(idcompleteObject,NSError*error )

{

@StrongObj(self);

[self.indicationstopAnimationWithLoadText:@"finish"withType:YES];

self.indication=nil;

if(!error){

//簽名信息以及訂單信息

NSString*String = [completeObjectobjectForKey:@"sign"];

NSString*orderSpec = [completeObjectobjectForKey:@"content"];

if([signisKindOfClass:[NSNullclass]] || sign ==nil){

[selfshowDissmissSelfAlertViewTitle:@""message:@"支付失敗,請(qǐng)重新嘗試。"complete:^{

}];

return;}

//urlcode加密

NSString*signedString = [selfurlEncodedString:String];

NSString*orderString ?=nil;

if(signedString !=nil){

//生成訂單信息及簽名請(qǐng)求參數(shù)

orderString = [NSStringstringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"",

orderSpec, signedString,@"RSA"];

}

//調(diào)用支付寶的SDK[[AlipaySDKdefaultService]payOrder:orderStringfromScheme:appSchemecallback:^(NSDictionary*resultDic){

//resultDic ?這個(gè)字典是返回我所有的支付成功或者失敗的信息

NSString* key =@"ResultStatus";

if(![[resultDicallKeys]containsObject:key]) {

key =@"resultStatus";

}

if(key !=nil){

//返回9000 就是成功

if([[resultDicobjectForKey:key]integerValue] ==9000) {

//訂單成功.

[selfpaySuccess];

}else{

//訂單失敗.

[selfpayFailed];

}

}

}];

}

}];

-(NSString*)urlEncodedString:(NSString*)string

{

NSString* encodedString = (__bridge_transferNSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridgeCFStringRef)string,NULL, (__bridgeCFStringRef)@"!*'();:@&=+$,/?%#[]",kCFStringEncodingUTF8);

returnencodedString;

}

集成

清楚了流程后,就好理解怎么集成了。

支付SDK

如果只需要發(fā)送訂單和處理支付返回結(jié)果,只需要添加AlipaySDK.bundle和AlipaySDK.framework就行了。

這里再吐槽下,之前用的舊版本,和現(xiàn)在的版本相比,還不光是把類(lèi)名字給改了,原先是用的類(lèi)方法,現(xiàn)在新版又給改成了單例了。。還真是任性啊,這要是哪家小廠(chǎng)的SDK,估計(jì)早被棄用了把。。

發(fā)送訂單的方法:

- (void)payOrder:(NSString *)orderStr

fromScheme:(NSString *)schemeStr

callback:(CompletionBlock)completionBlock;

如果手機(jī)內(nèi)沒(méi)安裝支付寶的app,會(huì)直接展現(xiàn)支付寶web支付界面,通過(guò)callback返回支付結(jié)果;

如果手機(jī)內(nèi)安裝了支付寶的app,會(huì)跳轉(zhuǎn)到支付寶的app支付,然后通過(guò)openURL的回調(diào)返回支付結(jié)果。

支付寶的SDK只給了一個(gè)處理返回結(jié)果的方法,而不像其他第三方的SDK提供一個(gè)處理openURL的方法,所以你需要通過(guò)DEMO或者在第二個(gè)文檔里找到處理openURL的方式:

if ([url.host isEqualToString:@"safepay"]) {

[[AlipaySDK defaultService] processOrderWithPaymentResult:url

standbyCallback:^(NSDictionary *resultDic) {

NSLog(@"result = %@",resultDic);

}]; }

SDK也提供了一個(gè)處理openURL返回結(jié)果的方法

- (void)processOrderWithPaymentResult:(NSURL *)resultUrl

standbyCallback:(CompletionBlock)completionBlock;

兩個(gè)回調(diào)block都統(tǒng)一定義為typedef void(^CompletionBlock)(NSDictionary *resultDic);,

返回了一個(gè)字典,但是SDK里完全沒(méi)有提示有哪些key。。

你可以在文檔里找到,或者自己實(shí)際試一下,返回的信息如下:

resultStatus,狀態(tài)碼,SDK里沒(méi)對(duì)應(yīng)信息,第一個(gè)文檔里有提到:

9000 訂單支付成功

8000 正在處理中

4000 訂單支付失敗

6001 用戶(hù)中途取消

6002 網(wǎng)絡(luò)連接出錯(cuò)

memo, 提示信息,比如狀態(tài)碼為6001時(shí),memo就是“用戶(hù)中途取消”。但千萬(wàn)別完全依賴(lài)這個(gè)信息,如果未安裝支付寶app,采用網(wǎng)頁(yè)支付時(shí),取消時(shí)狀態(tài)碼是6001,但這個(gè)memo是空的。。(當(dāng)我發(fā)現(xiàn)這個(gè)問(wèn)題的時(shí)候,我就決定,對(duì)于這么不靠譜的SDK,還是盡量靠自己吧。。)

result,訂單信息,以及簽名驗(yàn)證信息。如果你不想做簽名驗(yàn)證,那這個(gè)字段可以忽略了。。

如果你對(duì)支付的安全性不那么在意或重視的話(huà),到這里就可以完成支付寶的集成了。

如果想更加安全,還是需要增加下面的簽名驗(yàn)證的。

簽名驗(yàn)證

首先,RSA只是一種算法,所以你可以使用任何一種開(kāi)源的、或者自己去實(shí)現(xiàn)這個(gè)算法來(lái)實(shí)現(xiàn)簽名和驗(yàn)證的目的。

在整個(gè)流程當(dāng)中,因?yàn)樯婕暗搅薘SA公鑰、私鑰的生產(chǎn),RSA的簽名、驗(yàn)證簽名,SHA1值的計(jì)算,base64和URL編碼,所以支付寶用了一個(gè)開(kāi)源的代碼來(lái)統(tǒng)一解決這些問(wèn)題,就是openssl(順便再吐槽下,這DEMO里一放openssl,不知道又會(huì)引來(lái)多少公司的產(chǎn)品里使用openssl了,估計(jì)阿里自己也沒(méi)少用,什么時(shí)候都能跟老羅、華為一樣去贊助點(diǎn)呢。。)

如果你想省事,也用openssl,那你需要把這些東西都加入到項(xiàng)目中:DEMO中的openssl目錄頭文件,兩個(gè)庫(kù)文件libcrypto.a libssl.a,DEMO里支付寶自己寫(xiě)的Util目錄

訂單簽名

上面說(shuō)了,訂單簽名應(yīng)該用私鑰,但是把私鑰放到app里其實(shí)本身就不安全,因?yàn)槟愕腶pp是分發(fā)到用戶(hù)手里的,私鑰應(yīng)該放在自己的手里,分發(fā)出去的應(yīng)該是公鑰。

所以私鑰最好是放在自己的服務(wù)器上,訂單加密這個(gè)工作放在服務(wù)器端來(lái)做,服務(wù)器將包含簽名的訂單信息返回給app,app再通過(guò)SDK發(fā)送給支付寶,這樣會(huì)更安全些;而且服務(wù)器也能掌握所有的訂單狀況。

如果你非要將私鑰集成到app里,那可以參考SDK的DEMO,因?yàn)檫@個(gè)DEMO就是在app本地通過(guò)私鑰做的訂單簽名。。

支付結(jié)果簽名驗(yàn)證

上面的回調(diào)block提到了返回的內(nèi)容,返回的支付結(jié)果中的result字段里是帶有訂單信息和簽名信息的,所以簽名驗(yàn)證就是需要這個(gè)字段的值。

文檔中有一個(gè)這個(gè)字段的例子,實(shí)際結(jié)果沒(méi)有換行,我換一下行便于閱讀:

partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="測(cè)試"&body="測(cè)試測(cè)試"&total_fee="0.01"?ify_url="http://notify.msp.hk/notify.htm"&service="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30m"&success="true"&sign_type="RSA"&sign="hkFZr+zE9499nuqDNLZEF7W75RFFPsly876QuRSeN8WMaUgcdR00IKy5ZyBJ4eldhoJ/2zghqrD4E2G2mNjs3aE+HCLiBXrPDNdLKCZ gSOIqmv46TfPTEqopYfhs+o5fZzXxt34fwdrzN4mX6S13cr3UwmEV4L3Ffir/02RBVtU="

總共分為三個(gè)部分

第一部分是訂單信息,每個(gè)字段的具體含義可以在文檔里找;

中間sign_type是簽名用的算法,文檔里說(shuō)了,目前只支持RSA;

最后的sign就是簽名值。

驗(yàn)證的步驟如下:

首先把訂單信息和簽名值分別提取出來(lái)(SDK居然都不給處理好。。)

訂單信息就是sign_type的連字符&之前的所有字符串

簽名值是sign后面雙引號(hào)內(nèi)的內(nèi)容,注意簽名的結(jié)尾也是=,所以不要用split字符串的方式提取

如果你想簡(jiǎn)單,可以直接使用Util目錄下的DataVerifier來(lái)作簽名驗(yàn)證

- (BOOL)verifyString:(NSString *)string withSign:(NSString *)signString;

第一個(gè)參數(shù)就是訂單信息,第二個(gè)參數(shù)就是簽名值。

其實(shí)不使用openssl,用其他第三方RSA的開(kāi)源代碼也是可以的。可以看下DEMO里openssl_wrapper的源碼和SDK的文檔。

對(duì)于訂單信息,先做一個(gè)base64編碼(DEMO中這個(gè)還要調(diào)openssl來(lái)實(shí)現(xiàn)。。),再計(jì)算SHA1的值(這個(gè)也可以完全不用openssl,蘋(píng)果的庫(kù)中都有的。。),然后再簽名比對(duì)。

對(duì)于公鑰,如果使用其他第三方代碼,需要注意格式問(wèn)題。支付寶的DEMO實(shí)現(xiàn)中,是把這個(gè)公鑰又轉(zhuǎn)回成openssl生成的本地文件格式,然后再寫(xiě)入本地文件,再讓openssl讀取出來(lái)使用。。

以上,就是支付寶 iOS SDK的一些介紹。

總體來(lái)說(shuō),我覺(jué)得能靠自己處理的地方還是盡量不要依賴(lài)這個(gè)不太靠譜的SDK了。

微信支付步驟:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1#

郵件中參數(shù)API參數(shù)名詳細(xì)說(shuō)明

APPIDappidappid是微信公眾賬號(hào)或開(kāi)放平臺(tái)APP的唯一標(biāo)識(shí),在公眾平臺(tái)申請(qǐng)公眾賬號(hào)或者在開(kāi)放平臺(tái)申請(qǐng)APP賬號(hào)后,微信會(huì)自動(dòng)分配對(duì)應(yīng)的appid,用于標(biāo)識(shí)該應(yīng)用。可在微信公眾平臺(tái)-->開(kāi)發(fā)者中心查看,商戶(hù)的微信支付審核通過(guò)郵件中也會(huì)包含該字段值。

微信支付商戶(hù)號(hào)mch_id商戶(hù)申請(qǐng)微信支付后,由微信支付分配的商戶(hù)收款賬號(hào)。

API密鑰key交易過(guò)程生成簽名的密鑰,僅保留在商戶(hù)系統(tǒng)和微信支付后臺(tái),不會(huì)在網(wǎng)絡(luò)中傳播。商戶(hù)妥善保管該Key,切勿在網(wǎng)絡(luò)中傳輸,不能在其他客戶(hù)端中存儲(chǔ),保證key不會(huì)被泄漏。商戶(hù)可根據(jù)郵件提示登錄微信商戶(hù)平臺(tái)進(jìn)行設(shè)置。也可按一下路徑設(shè)置:微信商戶(hù)平臺(tái)(pay.weixin.qq.com)-->賬戶(hù)設(shè)置-->API安全-->密鑰設(shè)置

AppsecretsecretAppSecret是APPID對(duì)應(yīng)的接口密碼,用于獲取接口調(diào)用憑證access_token時(shí)使用。

商戶(hù)系統(tǒng)和微信支付系統(tǒng)主要交互說(shuō)明:

步驟1:用戶(hù)在商戶(hù)APP中選擇商品,提交訂單,選擇微信支付。

步驟2:商戶(hù)后臺(tái)收到用戶(hù)支付單,調(diào)用微信支付統(tǒng)一下單接口。參見(jiàn)【統(tǒng)一下單API】。

步驟3:統(tǒng)一下單接口返回正常的prepay_id,再按簽名規(guī)范重新生成簽名后,將數(shù)據(jù)傳輸給APP。參與簽名的字段名為appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式為Sign=WXPay

以上信息都是有后臺(tái)服務(wù)器調(diào)用微信的支付接口獲得并返給App端的

步驟4:商戶(hù)APP調(diào)起微信支付。api參見(jiàn)本章節(jié)【app端開(kāi)發(fā)步驟說(shuō)明

步驟5:商戶(hù)后臺(tái)接收支付通知。api參見(jiàn)【支付結(jié)果通知API

步驟6:商戶(hù)后臺(tái)查詢(xún)支付結(jié)果。,api參見(jiàn)【查詢(xún)訂單API

例子

NDHttpRequestManage*request = [NDHttpRequestManagerequestManage];

[requestuserGetWeiXinSign:[self.user.userIDndValue]AndTradeNo:_tradeNocomplete:^(idcompleteObject,NSError*error)

{

@StrongObj(self);

[self.indicationstopAnimationWithLoadText:@"finish"withType:YES];

self.indication=nil;

if(!error)

{

appDelegate.loginDone=nil;

NSString*str = completeObject[@"sign"];

[selfcheckSignFromSign:str];

NSData*jsonData = [strdataUsingEncoding:NSUTF8StringEncoding];

NSError*err;

NSDictionary*dict = [NSJSONSerializationJSONObjectWithData:jsonData

options:NSJSONReadingMutableContainers

error:&err];

NSMutableString*prepayId = [dictobjectForKey:@"prepayid"];

if(prepayId){

NSMutableString*stamp ?= [dictobjectForKey:@"timestamp"];

//調(diào)起微信支付

PayReq* req ? ? ? ? ? ? = [[PayReqalloc]init];

req.openID=[dictobjectForKey:@"appid"];

req.partnerId= [dictobjectForKey:@"partnerid"];

req.prepayId= [dictobjectForKey:@"prepayid"];

req.nonceStr= [dictobjectForKey:@"noncestr"];

req.timeStamp= stamp.intValue;

req.package=@"Sign=WXPay";

req.sign= [dictobjectForKey:@"sign"];

BOOLret = ? [WXApisendReq:req];

if(ret ==NO)

{

[selfshowDissmissSelfAlertViewTitle:@""message:@"支付失敗,請(qǐng)重新嘗試。"complete:^{

}];

}

}

}

}];

以下項(xiàng)目開(kāi)發(fā)環(huán)境以Xcode10.0,運(yùn)行環(huán)境為IOS7.0為例,說(shuō)明其開(kāi)發(fā)中需要的操作。

1、項(xiàng)目設(shè)置APPID

商戶(hù)在微信開(kāi)放平臺(tái)申請(qǐng)開(kāi)發(fā)APP應(yīng)用后,微信開(kāi)放平臺(tái)會(huì)生成APP的唯一標(biāo)識(shí)APPID。在Xcode中打開(kāi)項(xiàng)目,設(shè)置項(xiàng)目屬性中的URL Schemes為您的APPID。如圖8.7標(biāo)紅位置所示。

圖8.7

2、注冊(cè)APPID

商戶(hù)APP工程中引入微信lib庫(kù)和頭文件,調(diào)用API前,需要先向微信注冊(cè)您的APPID,代碼如下:

[WXApi registerApp:@"wxd930ea5d5a258f4f" withDescription:@"demo 2.0"];

3、調(diào)起支付

商戶(hù)服務(wù)器生成支付訂單,先調(diào)用【統(tǒng)一下單API】生成預(yù)付單,獲取到prepay_id后將參數(shù)再次簽名傳輸給APP發(fā)起支付。以下是調(diào)起微信支付的關(guān)鍵代碼:

PayReq *request = [[[PayReq alloc] init] autorelease];

request.partnerId = @"10000100";

request.prepayId= @"1101000000140415649af9fc314aa427";

request.package = @"Sign=WXPay";

request.nonceStr= @"a462b76e7436e98e0ed6e13c64b4fd1c";

request.timeStamp= @"1397527777";

request.sign= @"582282D72DD2B03AD892830965F428CB16E7A256";

[WXApi sendReq:request];

注意:該sign生成字段名列表見(jiàn)調(diào)起支付API

4、支付結(jié)果回調(diào)

照微信SDK Sample,在類(lèi)實(shí)現(xiàn)onResp函數(shù),支付完成后,微信APP會(huì)返回到商戶(hù)APP并回調(diào)onResp函數(shù),開(kāi)發(fā)者需要在該函數(shù)中接收通知,判斷返回錯(cuò)誤碼,如果支付成功則去后臺(tái)查詢(xún)支付結(jié)果再展示用戶(hù)實(shí)際支付結(jié)果。注意 一定不能以客戶(hù)端返回作為用戶(hù)支付的結(jié)果,應(yīng)以服務(wù)器端的接收的支付通知或查詢(xún)API返回的結(jié)果為準(zhǔn)。代碼示例如下:

-(void)onResp:(BaseResp*)resp{

if ([respisKindOfClass:[PayRespclass]]){

PayResp*response=(PayResp*)resp;

switch(response.errCode){

caseWXSuccess:

//服務(wù)器端查詢(xún)支付通知或查詢(xún)API返回的結(jié)果再提示成功

NSlog(@"支付成功");

break;

default:

NSlog(@"支付失敗,retcode=%d",resp.errCode);

break;

}

}

}

回調(diào)中errCode值列表:

名稱(chēng)描述解決方案

0成功展示成功頁(yè)面

-1錯(cuò)誤可能的原因:簽名錯(cuò)誤、未注冊(cè)APPID、項(xiàng)目設(shè)置APPID不正確、注冊(cè)的APPID與設(shè)置的不匹配、其他異常等。

-2用戶(hù)取消無(wú)需處理。發(fā)生場(chǎng)景:用戶(hù)不支付了,點(diǎn)擊取消,返回APP。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容