整合支付寶錢包支付 iOS SDK 的方法與經驗

發表於2016-11-16

沒想到,支付寶的SDK是我目前用過的所有第三方SDK中最難用的一個了。

下載

首先,你要想找到這個SDK,都得費點功夫。現在的SDK改名叫移動支付整合開發包了,下載頁面在 這裡 的 “請點此下載整合開發包

Baidu和Googlep排在前面的支付寶開放平臺,裡面的SDK已經是2年前的版本了,而且還不支援64位架構。

文件

壓縮包裡有兩個相關文件 :
《支付寶錢包支付介面開發包2.0標準版.pdf》
《支付寶錢包支付介面開發包2.0標準版接入與使用規則.pdf》
iOS相關內容可以主要看第一個文件,第二個文件名字和裡面寫的不一樣,內容其實是個附錄;文件裡面多個平臺都涉及到了,內容有些雜亂。下面先解釋下整體SDK的流程和要做的事,就好對症下藥找文件內相應的內容了。

流程

摘自第一個文件《支付寶錢包支付介面開發包2.0標準版.pdf》

11185792-ec4290951fa39551
業務流程圖

圖中的“商戶客戶端”就是我們的iOS客戶端需要做的事情:

  • 呼叫支付寶支付介面
  • 處理支付寶返回的支付結果

在呼叫支付寶支付介面前,我們還需要先生成一個訂單,文件中描述時,是將這步也放在客戶端來做了,但也可以在伺服器端生成這個訂單(圖中支付寶會在支付成功後通知伺服器端,所以在伺服器端生成訂單的話,你可以掌握所有訂單,而且也會更安全):

  • 生成訂單(可以在iOS客戶端內生成,也可以在伺服器端生成)
  • 呼叫支付寶支付介面,傳送訂單
  • 處理支付寶返回的支付結果

其實對於業務來說,這些步驟已經夠了,但是有一個安全性問題,你肯定不希望你接收到的支付結果被截獲修改,所以,這就需要在生成訂單和處理支付結果的時候做一個安全性校驗:
生成訂單時對資料簽名,收到支付結果時對資料進行簽名驗證,以檢驗資料是否被篡改過。
支付寶目前只支援採用RSA加密方式做簽名驗證。

RSA加密演算法 除了可加解密外,還可用來作簽名校驗。
簡單的說,RSA會生成一個私鑰和一個公鑰,私鑰你應該獨自保管,公鑰你可以分發出去。
做簽名驗證時,你可以用私鑰對需要傳輸的資料做簽名加密,生成一個簽名值,之後分發資料,接收方通過公鑰對簽名值做校驗,如果一致則認為資料無篡改。

具體到支付寶使用RSA做簽名驗證,就是在生產訂單時,需要使用私鑰生成簽名值;在處理返回的支付結果時,需要使用公鑰驗證返回結果是否被篡改了。
具體需要對哪些值,怎樣生成簽名,對哪些值最簽名驗證,可以在第一個文件中找找,後面我會簡單提一下,但還是以文件或實踐為準吧。

整合

清楚了流程後,就好理解怎麼整合了。

支付SDK

如果只需要傳送訂單和處理支付返回結果,只需要新增AlipaySDK.bundleAlipaySDK.framework就行了。

這裡再吐槽下,之前用的舊版本,和現在的版本相比,還不光是把類名字給改了,原先是用的類方法,現在新版又給改成了單例了。。還真是任性啊,這要是哪家小廠的SDK,估計早被棄用了把。。

傳送訂單的方法:

  • 如果手機內沒安裝支付寶的app,會直接展現支付寶web支付介面,通過callback返回支付結果;
  • 如果手機內安裝了支付寶的app,會跳轉到支付寶的app支付,然後通過openURL的回撥返回支付結果。

支付寶的SDK只給了一個處理返回結果的方法,而不像其他第三方的SDK提供一個處理openURL的方法,所以你需要通過DEMO或者在第二個文件裡找到處理openURL的方式:

SDK也提供了一個處理openURL返回結果的方法

兩個回撥block都統一定義為typedef void(^CompletionBlock)(NSDictionary *resultDic);
返回了一個字典,但是SDK裡完全沒有提示有哪些key。。
你可以在文件裡找到,或者自己實際試一下,返回的資訊如下:

  • resultStatus,狀態碼,SDK裡沒對應資訊,第一個文件裡有提到:
    • 9000 訂單支付成功
    • 8000 正在處理中
    • 4000 訂單支付失敗
    • 6001 使用者中途取消
    • 6002 網路連線出錯
  • memo, 提示資訊,比如狀態碼為6001時,memo就是“使用者中途取消”。但千萬別完全依賴這個資訊,如果未安裝支付寶app,採用網頁支付時,取消時狀態碼是6001,但這個memo是空的。。(當我發現這個問題的時候,我就決定,對於這麼不靠譜的SDK,還是儘量靠自己吧。。)
  • result,訂單資訊,以及簽名驗證資訊。如果你不想做簽名驗證,那這個欄位可以忽略了。。

如果你對支付的安全性不那麼在意或重視的話,到這裡就可以完成支付寶的整合了。
如果想更加安全,還是需要增加下面的簽名驗證的。

簽名驗證

首先,RSA只是一種演算法,所以你可以使用任何一種開源的、或者自己去實現這個演算法來實現簽名和驗證的目的。

在整個流程當中,因為涉及到了RSA公鑰、私鑰的生產,RSA的簽名、驗證簽名,SHA1值的計算,base64和URL編碼,所以支付寶用了一個開源的程式碼來統一解決這些問題,就是openssl(順便再吐槽下,這DEMO裡一放openssl,不知道又會引來多少公司的產品裡使用openssl了,估計阿里自己也沒少用,什麼時候都能跟老羅、華為一樣去贊助點呢。。)

如果你想省事,也用openssl,那你需要把這些東西都加入到專案中:DEMO中的openssl目錄標頭檔案,兩個庫檔案libcrypto.a libssl.a,DEMO裡支付寶自己寫的Util目錄

訂單簽名

上面說了,訂單簽名應該用私鑰,但是把私鑰放到app裡其實本身就不安全,因為你的app是分發到使用者手裡的,私鑰應該放在自己的手裡,分發出去的應該是公鑰。
所以私鑰最好是放在自己的伺服器上,訂單加密這個工作放在伺服器端來做,伺服器將包含簽名的訂單資訊返回給app,app再通過SDK傳送給支付寶,這樣會更安全些;而且伺服器也能掌握所有的訂單狀況。

如果你非要將私鑰整合到app裡,那可以參考SDK的DEMO,因為這個DEMO就是在app本地通過私鑰做的訂單簽名。。

支付結果簽名驗證

上面的回撥block提到了返回的內容,返回的支付結果中的result欄位裡是帶有訂單資訊和簽名資訊的,所以簽名驗證就是需要這個欄位的值。

文件中有一個這個欄位的例子,實際結果沒有換行,我換一下行便於閱讀:

總共分為三個部分

  • 第一部分是訂單資訊,每個欄位的具體含義可以在文件裡找;
  • 中間sign_type是簽名用的演算法,文件裡說了,目前只支援RSA;
  • 最後的sign就是簽名值。

驗證的步驟如下:

  • 首先把訂單資訊和簽名值分別提取出來(SDK居然都不給處理好。。)
    • 訂單資訊就是sign_type的連字元&之前的所有字串
    • 簽名值是sign後面雙引號內的內容,注意簽名的結尾也是=,所以不要用split字串的方式提取
  • 如果你想簡單,可以直接使用Util目錄下的DataVerifier來作簽名驗證
    • - (BOOL)verifyString:(NSString *)string withSign:(NSString *)signString;
    • 第一個引數就是訂單資訊,第二個引數就是簽名值。

其實不使用openssl,用其他第三方RSA的開原始碼也是可以的。可以看下DEMO裡openssl_wrapper的原始碼和SDK的文件。

  • 對於訂單資訊,先做一個base64編碼(DEMO中這個還要調openssl來實現。。),再計算SHA1的值(這個也可以完全不用openssl,蘋果的庫中都有的。。),然後再簽名比對。
  • 對於公鑰,如果使用其他第三方程式碼,需要注意格式問題。支付寶的DEMO實現中,是把這個公鑰又轉回成openssl生成的本地檔案格式,然後再寫入本地檔案,再讓openssl讀取出來使用。。

以上,就是支付寶 iOS SDK的一些介紹。
總體來說,我覺得能靠自己處理的地方還是儘量不要依賴這個不太靠譜的SDK了。。

相關文章