关于iOS开发支付宝集成,客户端签名与验证

请各位在看此教程之前请确保你的工程已经集成官方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:");

不推荐客户端验证,应该由后台来做(对我们客户端来说既安全又省事)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容