请各位在看此教程之前请确保你的工程已经集成官方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:");
不推荐客户端验证,应该由后台来做(对我们客户端来说既安全又省事)