以下是IOS项目中集成支付宝的过程总结,如有冲突,请以支付宝的文档为准
一、集成大致流程:
1、商户服务端使用openssl生成自己的公钥和私钥,
2、商户真正使用的是:商户私钥,支付付公钥
3、APP端使用是服务端openssl生成的公钥和私钥的内容字符串(私钥需是PKS8格式)
4、商户上传公钥给支付宝,支付宝把公钥给商户,完成公钥交换操作
5、使用时,APP端使用用私钥做签名,发起商品支付,支付宝根据商户上传的公钥做验证签名,
6、商户使用支付宝公钥接收支付宝访问的
kNotifyURL做验证签名认证,确认一次订单流程处理完成时
二、涉及角色:
1)、商户服务端(JAVA或PHP后台服务器):
2)、商户客户端(IOS)
3)、支付宝:
三、服务器端操作流程
1、先生成私钥rsa_private_key.pem:
OpenSSL> genrsa -out rsa_private_key.pem 1024
Generating RSA private key, 1024 bit long modulus
.................++++++
.......++++++
e is 65537 (0x10001)
OpenSSL>
2、生成公钥rsa_public_key.pem:()
OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
writing RSA key
OpenSSL>
3、生成PKCS编码的私钥:(APP端要用)
OpenSSL> pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMB1Cx+PSty0aJYx
rQTz3ecmQ4DsCqKjytK3ip7iG+0jAGedlbSXURQIxebBEClXy1og0gb76iLpm6pv
I4K7ZVPJtcteHk0Glhivqq+16tnivjaq9V89BR6iJoepFyRHobJ1jqBptzgyGc/s
J+7d6iFex27tG3IUz7DYNVgFzkYtAgMBAAECgYAmvKgzfvz7dViDupXvpEIqz1nQ
7jGp0Lv3M7g0CKDEV0IymNZUFgzcsnNa4csl9yTYDDkZ7MSQqGKLqHkGTD+1hyH3
CTq7a5LQ8h7aAdzFhibtQsZu8eM/MP5nHZCCYACYfbu64Dg+8fZ/pnZQ1Ri13w7H
4wf7L1UAxjPhgnHWwQJBAOw86NQgeBkBSMBcMrGcnHXoYEPsC834jqC/UatqRyL9
9COuV1QSbjcKtgaC3OFWpjTGROWC8hxihncXKf0wCr0CQQDQjo84Y40xdoboJjdK
2uBPnmcRv3LAL83t2T7NarmyGVxYljJNL0Z+OTPsPnB91jQecdLqHme5iyXGn8Rf
7JgxAkEA0XdYgu6fTpyi411c3budx7ZZ1R/xf5pK7SF2yuUbWl2PIiwt5q/I5ikr
KS7Tp0JrcRP0dwTapGyACgySAJueiQJAJxgiFsLqi7QZM9k+EiUXWTVrQrNtkkMj
ygsoL59q8cy5N83n3foXr7+PUSCfO6d0m6RgkgxjCy/fQ+1dBVI3cQJBALs9IuQ/
1lPJV+8CWm6wDjtNg1SWE2kxI3X5Ym8nkmXijY+pf9MtIRiVX1gQvWVp3S9sVFlk
w3hN3ldmCXcCnlI=
-----END PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMB1Cx+PSty0aJYx
rQTz3ecmQ4DsCqKjytK3ip7iG+0jAGedlbSXURQIxebBEClXy1og0gb76iLpm6pv
I4K7ZVPJtcteHk0Glhivqq+16tnivjaq9V89BR6iJoepFyRHobJ1jqBptzgyGc/s
J+7d6iFex27tG3IUz7DYNVgFzkYtAgMBAAECgYAmvKgzfvz7dViDupXvpEIqz1nQ
7jGp0Lv3M7g0CKDEV0IymNZUFgzcsnNa4csl9yTYDDkZ7MSQqGKLqHkGTD+1hyH3
CTq7a5LQ8h7aAdzFhibtQsZu8eM/MP5nHZCCYACYfbu64Dg+8fZ/pnZQ1Ri13w7H
4wf7L1UAxjPhgnHWwQJBAOw86NQgeBkBSMBcMrGcnHXoYEPsC834jqC/UatqRyL9
9COuV1QSbjcKtgaC3OFWpjTGROWC8hxihncXKf0wCr0CQQDQjo84Y40xdoboJjdK
2uBPnmcRv3LAL83t2T7NarmyGVxYljJNL0Z+OTPsPnB91jQecdLqHme5iyXGn8Rf
7JgxAkEA0XdYgu6fTpyi411c3budx7ZZ1R/xf5pK7SF2yuUbWl2PIiwt5q/I5ikr
KS7Tp0JrcRP0dwTapGyACgySAJueiQJAJxgiFsLqi7QZM9k+EiUXWTVrQrNtkkMj
ygsoL59q8cy5N83n3foXr7+PUSCfO6d0m6RgkgxjCy/fQ+1dBVI3cQJBALs9IuQ/
1lPJV+8CWm6wDjtNg1SWE2kxI3X5Ym8nkmXijY+pf9MtIRiVX1gQvWVp3S9sVFlk
w3hN3ldmCXcCnlI=
-----END PRIVATE KEY-----
OpenSSL>
4、
查看公钥内容:(APP端要用,
BEGIN 和END之间的内容)
localhost:bin zhisheshe$ openssl rsa -inform PEM -in rsa_public_key.pem -pubin -text
Modulus (1024 bit):
00:c0:75:0b:1f:8f:4a:dc:b4:68:96:31:ad:04:f3:
dd:e7:26:43:80:ec:0a:a2:a3:ca:d2:b7:8a:9e:e2:
1b:ed:23:00:67:9d:95:b4:97:51:14:08:c5:e6:c1:
10:29:57:cb:5a:20:d2:06:fb:ea:22:e9:9b:aa:6f:
23:82:bb:65:53:c9:b5:cb:5e:1e:4d:06:96:18:af:
aa:af:b5:ea:d9:e2:be:36:aa:f5:5f:3d:05:1e:a2:
26:87:a9:17:24:47:a1:b2:75:8e:a0:69:b7:38:32:
19:cf:ec:27:ee:dd:ea:21:5e:c7:6e:ed:1b:72:14:
cf:b0:d8:35:58:05:ce:46:2d
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAdQsfj0rctGiWMa0E893nJkOA
7Aqio8rSt4qe4hvtIwBnnZW0l1EUCMXmwRApV8taINIG++oi6ZuqbyOCu2VTybXL
Xh5NBpYYr6qvterZ4r42qvVfPQUeoiaHqRckR6GydY6gabc4MhnP7Cfu3eohXsdu
7RtyFM+w2DVYBc5GLQIDAQAB
00:c0:75:0b:1f:8f:4a:dc:b4:68:96:31:ad:04:f3:
dd:e7:26:43:80:ec:0a:a2:a3:ca:d2:b7:8a:9e:e2:
1b:ed:23:00:67:9d:95:b4:97:51:14:08:c5:e6:c1:
10:29:57:cb:5a:20:d2:06:fb:ea:22:e9:9b:aa:6f:
23:82:bb:65:53:c9:b5:cb:5e:1e:4d:06:96:18:af:
aa:af:b5:ea:d9:e2:be:36:aa:f5:5f:3d:05:1e:a2:
26:87:a9:17:24:47:a1:b2:75:8e:a0:69:b7:38:32:
19:cf:ec:27:ee:dd:ea:21:5e:c7:6e:ed:1b:72:14:
cf:b0:d8:35:58:05:ce:46:2d
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAdQsfj0rctGiWMa0E893nJkOA
7Aqio8rSt4qe4hvtIwBnnZW0l1EUCMXmwRApV8taINIG++oi6ZuqbyOCu2VTybXL
Xh5NBpYYr6qvterZ4r42qvVfPQUeoiaHqRckR6GydY6gabc4MhnP7Cfu3eohXsdu
7RtyFM+w2DVYBc5GLQIDAQAB
-----END PUBLIC KEY-----
5、把
BEGIN 和END之间的内容(整理成一行,前后不能有回车、换行)上传到服务器,换回支付宝的公钥
四、APP端
1、添加相关信息,一般写一个头文件 AlipayHeader.h
/**
* partner: 合作身份者 ID, 以 2088 开头由 16 位纯数字组成的字符串。
*
*/
#define kPartnerID @ "2088811123293271"
/**
* seller: 支付宝收款账号 , 手机号码或邮箱格式。
* partner: 合作身份者 ID, 以 2088 开头由 16 位纯数字组成的字符串。
*
*/
#define kPartnerID @ "2088811123293271"
/**
* seller: 支付宝收款账号 , 手机号码或邮箱格式。
*/
/**
* 支付宝服务器主动通知商户 网站里指定的页面 http 路径。
*/
#define kNotifyURL @
"http://www.test.com/Home/Pay/notify_src"
/**
* appSckeme: 应用注册 scheme, 在 Info.plist 定义 URLtypes ,处理支付宝回调
*/
#define kAppScheme @
“test1111"
/**
* private_key: 商户方的私钥 ,pkcs8 格式。
*/
#define kPartnerPrivateKey @
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMKpx/mf1PdrZ5QxbDd0qUOZ143Msyne4DH0fhXwKXh3I/1TO258e5gObaoLKCBF3sP8Fp0AUmSnKL3fiovC9JUv0at/s/Q+zw4h/ZbgSCqsvAxZE52eukFlpZn1SgDW65qhwzt9u6N4iYPmVF+RdS3lwAs163C0jRKLcMPGO1MZAgMBAAECgYBgqKlxnBnFmYFfJoNTrgv2U0ejU4eLPO4aIAsTnaMZ/B7UxSV3oTxFrrRpgQy1qbwJmP0pjGVdMVubnIpRB8cmBx5vZZGfNUBFCOddevJASNzHP2ILSxXpVlLHU+fxuHtjaq+gscCT+kxGjUs81hoAwZK2Kj+QNfVPF9+5M6qIgWp0RJFSsMe3w5SAYSRVYQJAMOnk+yP0I6EzT/gjVo85eoBK4/Gm7Vl5S+JZfvbQEwng8OILW0EVCHno3lm+lzR3t2oZhLlFz0zktUUGsqrbzA=="
/**
* public_key:
1 、移动端用服务器产生的公钥
2 、服务端的公钥使用支付宝产生的公钥 ,
*/
#define kAliPayPubliceKey @ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCqcf5n9T3a2eUMWw3dKlDmdeNzLMp3uAx9H4V8Cl4dyP9UztufHuYDm2qCyggRd7D/BadAFJkpyi934qLwvSVL9Grf7P0Ps8OIf2W4EgqrLwMWROdnrpBZaWZ9UoA1uuaocM7fbujeImD5lRfkXUt5cALNetwtI0Si3DDxjtTGQIDAQAB"
2、封装订单信息,单独封装一个类,比如AlipayRequestConfig
//
仅含有变化的参数
+ ( void )alipayWithPartner:( NSString *)partner
seller:( NSString *)seller
tradeNO:( NSString *)tradeNO
productName:( NSString *)productName
productDescription:( NSString *)productDescription
amount:( NSString *)amount
notifyURL:( NSString *)notifyURL
itBPay:( NSString *)itBPay {
[ self alipayWithPartner :partner seller :seller
tradeNO :tradeNO
productName :productName
productDescription :productDescription
amount :amount
notifyURL :notifyURL
service : @"mobile.securitypay.pay"
paymentType : @"1" inputCharset : @"UTF-8"
itBPay :itBPay privateKey : kPartnerPrivateKey
appScheme : kAppScheme ];
}
// 包含所有必要的参数
+ ( void )alipayWithPartner:( NSString *)partner
seller:( NSString *)seller
tradeNO:( NSString *)tradeNO
productName:( NSString *)productName
productDescription:( NSString *)productDescription
amount:( NSString *)amount
notifyURL:( NSString *)notifyURL
service:( NSString *)service
paymentType:( NSString *)paymentType
inputCharset:( NSString *)inputCharset
itBPay:( NSString *)itBPay
privateKey:( NSString *)privateKey
appScheme:( NSString *)appScheme {
Order *order = [ Order order ];
order. partner = partner;
order. seller = seller;
order. tradeNO = tradeNO;
order. productName = productName;
order. productDescription = productDescription;
order. amount = amount;
order. notifyURL = notifyURL;
order. service = service;
order. paymentType = paymentType;
order. inputCharset = inputCharset;
order. itBPay = itBPay;
// 将商品信息拼接成字符串
NSString *orderSpec = [order description ];
// 获取私钥并将商户信息签名 , 外部商户可以根据情况存放私钥和签名 , 只需要遵循 RSA 签名规范 , 并将签名字符串 base64 编码和 UrlEncode
NSString *signedString = [ self genSignedStringWithPrivateKey : kPartnerPrivateKey OrderSpec :orderSpec];
// 调用支付接口
[ self payWithAppScheme :appScheme orderSpec :orderSpec signedString :signedString];
}
// 生成 signedString
+ ( NSString *)genSignedStringWithPrivateKey:( NSString *)privateKey OrderSpec:( NSString *)orderSpec {
// 获取私钥并将商户信息签名 , 外部商户可以根据情况存放私钥和签名 , 只需要遵循 RSA 签名规范 , 并将签名字符串 base64 编码和 UrlEncode
id < DataSigner > signer = CreateRSADataSigner (privateKey);
return [signer signString :orderSpec];
}
// 支付
+ ( void )payWithAppScheme:( NSString *)appScheme orderSpec:( NSString *)orderSpec signedString:( NSString *)signedString {
// 将签名成功字符串格式化为订单字符串 , 请严格按照该格式
NSString *orderString = nil ;
if (signedString != nil ) {
orderString = [ NSString stringWithFormat : @"%@&sign=\"%@\"&sign_type=\"%@\"" , orderSpec, signedString, @"RSA" ];
[[ AlipaySDK defaultService ] payOrder :orderString fromScheme :appScheme callback :^( NSDictionary *resultDic) {
NSLog ( @"AliPay-reslut = %@" ,resultDic);
}];
}
}
+ ( void )alipayWithPartner:( NSString *)partner
seller:( NSString *)seller
tradeNO:( NSString *)tradeNO
productName:( NSString *)productName
productDescription:( NSString *)productDescription
amount:( NSString *)amount
notifyURL:( NSString *)notifyURL
itBPay:( NSString *)itBPay {
[ self alipayWithPartner :partner seller :seller
tradeNO :tradeNO
productName :productName
productDescription :productDescription
amount :amount
notifyURL :notifyURL
service : @"mobile.securitypay.pay"
paymentType : @"1" inputCharset : @"UTF-8"
itBPay :itBPay privateKey : kPartnerPrivateKey
appScheme : kAppScheme ];
}
// 包含所有必要的参数
+ ( void )alipayWithPartner:( NSString *)partner
seller:( NSString *)seller
tradeNO:( NSString *)tradeNO
productName:( NSString *)productName
productDescription:( NSString *)productDescription
amount:( NSString *)amount
notifyURL:( NSString *)notifyURL
service:( NSString *)service
paymentType:( NSString *)paymentType
inputCharset:( NSString *)inputCharset
itBPay:( NSString *)itBPay
privateKey:( NSString *)privateKey
appScheme:( NSString *)appScheme {
Order *order = [ Order order ];
order. partner = partner;
order. seller = seller;
order. tradeNO = tradeNO;
order. productName = productName;
order. productDescription = productDescription;
order. amount = amount;
order. notifyURL = notifyURL;
order. service = service;
order. paymentType = paymentType;
order. inputCharset = inputCharset;
order. itBPay = itBPay;
// 将商品信息拼接成字符串
NSString *orderSpec = [order description ];
// 获取私钥并将商户信息签名 , 外部商户可以根据情况存放私钥和签名 , 只需要遵循 RSA 签名规范 , 并将签名字符串 base64 编码和 UrlEncode
NSString *signedString = [ self genSignedStringWithPrivateKey : kPartnerPrivateKey OrderSpec :orderSpec];
// 调用支付接口
[ self payWithAppScheme :appScheme orderSpec :orderSpec signedString :signedString];
}
// 生成 signedString
+ ( NSString *)genSignedStringWithPrivateKey:( NSString *)privateKey OrderSpec:( NSString *)orderSpec {
// 获取私钥并将商户信息签名 , 外部商户可以根据情况存放私钥和签名 , 只需要遵循 RSA 签名规范 , 并将签名字符串 base64 编码和 UrlEncode
id < DataSigner > signer = CreateRSADataSigner (privateKey);
return [signer signString :orderSpec];
}
// 支付
+ ( void )payWithAppScheme:( NSString *)appScheme orderSpec:( NSString *)orderSpec signedString:( NSString *)signedString {
// 将签名成功字符串格式化为订单字符串 , 请严格按照该格式
NSString *orderString = nil ;
if (signedString != nil ) {
orderString = [ NSString stringWithFormat : @"%@&sign=\"%@\"&sign_type=\"%@\"" , orderSpec, signedString, @"RSA" ];
[[ AlipaySDK defaultService ] payOrder :orderString fromScheme :appScheme callback :^( NSDictionary *resultDic) {
NSLog ( @"AliPay-reslut = %@" ,resultDic);
}];
}
}
3、封装支付接口,可以写在业务层,也可单独封装起来,此处写在业务层
- (
void
)aliPayWithOderID:(
NSString
*)orderID price:(
NSString
*)price{
[ AlipayRequestConfig alipayWithPartner : kPartnerID
seller : kSellerID
[ AlipayRequestConfig alipayWithPartner : kPartnerID
seller : kSellerID
tradeNO:orderID
productName:@“商品名
"
productDescription
:
@"
二手车
"
amount :price
notifyURL : kNotifyURL
amount :price
notifyURL : kNotifyURL
itBPay:@"30m"];
}
4、发起支付
[
self
aliPayWithOderID
:
@"fwrwr131313154141"
price
:
@"8000"
];