請各位在看此教程之前請確保你的工程已經集成官方SDK成功,并且沒有報錯。本教程主要解決簽名和驗證的問題。
首先說一下簡單支付流程:你提交等待支付的訂單信息給支付寶,支付寶返回訂單支付結果給你(這里暫時先不考慮服務器)。但是這里就有安全問題了,支付寶怎么知道你提交的訂單信息商家的真實性?你又怎么知道支付寶返回的結果是支付寶官方操作而不是被篡改過的呢?
所以就有了安全驗證一說,也就是私鑰和公鑰了。商家和支付寶都有一對公鑰和私鑰,支付寶的公鑰提供給了每個商家(現在是統一的),商家的公鑰在生成時也是應該提交到了支付寶的。私鑰都是自己留著,不給別人。私鑰用來數字簽名,公鑰用來對私鑰簽過名的信息做驗證。
所以為了安全,你需要在發送訂單信息的時候用你的私鑰簽名,發送給支付寶,支付寶用你的公鑰去驗證你的訂單是否是本人。然后支付寶返回用支付寶私鑰簽名過的支付結果給你,你這個時候就需要用支付寶公鑰去驗證到底是不是真正的支付寶返回的信息。
1、支付的代碼
//我的demo是一個觸摸事件調用支付
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
/*=======================需要填寫商戶app申請的===================================*/
/*============================================================================*/
//這些信息官方推薦放在服務器端,當然對訂單簽名最好也讓服務器去做,這里是為方便簽名就放在了客戶端
NSString * partner = @"2088121307144063";
NSString * seller = @"service@9elephas.com";
NSString * privateKey = @"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOnoBOH1X12iygvB 5LraNgIi4vRTHWQMxGBsrCn/rq8PaYsh+c3DPk01CVn0CtRuqPKX8sDKATnmef8X OmIBb5jQORZ4euIBW9vFDJ8TScb5gFd9UM9JbccFA5P++wj0Kd1NVRFUSdyd0PQk w61tXc3sUk0KBYfiVGJwhUiw9FJjAgMBAAECgYALwMHGDMs+7DgUwShaDy7ZiqE2 v5phdZbEdZFtBtDjMPYPrKRdp2rQ/FI899s3c1v/3IyxDTVkkGUe4S7oz8OopGgJ uY4+NUmXBZve7Cl831OaFp++dUTcNT1r7OiYF13FWdMK/HlojJSN4Ub1+AyBmMxx LFPTokepprGNMboKuQJBAP/z+gfhtcqxmC7oWGkc5oYePPbgUABs1RZPInekyQat 9zylIRrsklG8lAsIJLky5etUDv3z3TzRRx7U6XKv1ccCQQDp8wG6iD5dFa10LWh6 uLrCzBwP+cfk2VaFZSKYofgZL1ibz/t0zir39MbjA/ga+0deM382NFeIkc4YTPNR S66FAkB94phB0iBgTdKkl4AMSruSkUK4xYBzhROUwl0YbUK191AXUrwiiuI4M0C4 4Et3jvIIOTKacpuIcwHAx0T+ND83AkAbG8d1f9gKHTruHVzf64voipIt37mj8PMv ndp2aT5AXNYdp+nxTPp5pOlu4MTdC4Tni3wQIdyKvKpu8mu3XdepAkEAuVb0BhKT 01A+Ihqa0N9KBXm5gZPxkN9at6ThtcHpuNiUWVdL5YXFODIfB0SVcj+FTOWVzlPV 6wj97n+ewacH4w==";
//支付寶公鑰(目前所有支付寶公鑰都是這個)
NSString* key = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRAFljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQEB/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5KsiNG9zpgmLCUYuLkxpLQIDAQAB";
//這個方法應該是初始化公鑰并保存到本地吧
id<DataVerifier> verifier = CreateRSADataVerifier(key);
Order *order = [[Order alloc] init];
order.partner = partner;
order.seller = seller;
order.tradeNO = [self generateTradeNO]; //訂單ID(由商家自行制定)
order.productName = @"淘寶訂單"; //商品標題
order.productDescription = @"一級棒"; //商品描述
order.amount = @"0.01"; //商品價格
order.notifyURL = @"http://www.baidu.com"; //回調URL(由于是demo我隨便填的,我也是剛開始做支付,我也不知道是什么意思,請各位網友指出)
order.service = @"mobile.securitypay.pay";
order.paymentType = @"1";
order.inputCharset = @"utf-8";
order.itBPay = @"30m";
//應用注冊scheme,在AlixPayDemo-Info.plist定義URL types
NSString *appScheme = @"xiongchaozhifu";//我這里是隨便填的,應該填自己應用相關的字符,別忘了在工程info設置——URL Types下也填寫Schemes,不然支付完成之后無法跳轉回來
//將商品信息拼接成字符串
NSString *orderSpec = [order description];
NSLog(@"簽名之前訂單:%@",orderSpec);
//獲取私鑰并將商戶信息簽名,外部商戶可以根據情況存放私鑰和簽名,只需要遵循RSA簽名規范,并將簽名字符串base64編碼和UrlEncode
id<DataSigner> signer = CreateRSADataSigner(privateKey);
NSString *signedString = [signer signString:orderSpec];
//將簽名成功字符串格式化為訂單字符串,請嚴格按照該格式
NSString *orderString = nil;
if (signedString != nil)
{
orderString = [NSString stringWithFormat:@"%@&sign=\\"%@\\"&sign_type=\\"%@\\"",
orderSpec, signedString, @"RSA"];
NSLog(@"簽名之后訂單:%@",orderString);
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic)
{//這里的支付結果是在沒有安裝支付寶客服端的情況下跳轉網頁支付時,會在這回調
NSLog(@"返回結果resultDic = %@",resultDic);
if (resultDic)
{
/*
9000 訂單支付成功
8000 正在處理中
4000 訂單支付失敗
6001 用戶中途取消
6002 網絡連接出錯
*/
if ([resultDic[@"resultStatus"]integerValue] == 9000)
//網上很多教程到這里就結束了,因為他們沒有驗證返回訂單簽名
{
//驗簽
//去掉返回字典中result值里面的“\\”
NSString *result = [resultDic[@"result"] stringByReplacingOccurrencesOfString:@"\\\\" withString:@""];
//分割字符串獲取訂單信息和簽名
NSArray *array = [result componentsSeparatedByString:@"&sign_type=\\"RSA\\"&sign=\\""];
//返回的訂單信息
NSString *orderString = array[0];
//返回的訂單簽名
NSString *signedString = [array[1] substringToIndex:[array[1]length]-1];
//驗證返回信息與簽名
if ([verifier verifyString:orderString withSign:signedString])
{
//驗證簽名成功,交易結果無篡改
NSLog(@"------------支付成功---------------");
}
else
{
//驗簽錯誤
}
}
}
else
{
//交易失敗
}
}];
}
}
最后提示:我上面的簽名與驗證都是在客戶端做的,實際開發中推薦放在服務器中。
2、下面貼上AppDelegate中相關方法
//跳轉支付寶支付(安裝了支付寶客戶端的情況)時,支付完成之后重新回到本app會調用此方法,在此可以根據resultDic提示支付結果
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
{
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
**驗證方式同上面的網頁支付**
}];
}
return YES;
}
提示:網上相關教程可能是下面兩個方法,但在9.0以上好像被移除了,現在最新的是上面那個方法
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url NS_DEPRECATED_IOS(2_0, 9_0, "Please use application:openURL:options:");
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation NS_DEPRECATED_IOS(4_2, 9_0, "Please use application:openURL:options:");
不推薦客戶端驗證,應該由后臺來做(對我們客戶端來說既安全又省事)