商户(例如:是某个电商网站)对开发者进行应用授权后,开发者可以帮助商户完成相应的业务逻辑,例如代替商户发起当面付的收单请求。
2、授权采用标准的OAuth 2.0流程。
3、要进行第三方调用,开发者需要在应用中添加对应功能并获得商户授权,商户需要申请开通相应的权限(例如对于当面付,开发者只需在应用中添加“当面付”功能并获得商户授权,商户则需要开通“当面付”产品,之后开发者就可以帮助商户发起当面付的收单请求)。
上传应用公钥并获取支付宝公钥,(https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.TvAv9s&treeId=291&articleId=105972&docType=1);支付宝公钥内容,在代码中验签使用。
服务端的SDK,签名和验签(https://doc.open.alipay.com/docs/doc.htm?treeId=54&articleId=103419&docType=1);
开发者调用接口前需要先生成RSA密钥,RSA密钥包含应用私钥(APP_PRIVATE_KEY)、应用公钥(APP_PUBLIC_KEY)。生成密钥后在开放平台开发者中心进行密钥配置,配置完成后可以获取支付宝公钥(ALIPAY_PUBLIC_KEY)。
WINDOWS
MAC_OSX
下载该工具后,解压打开文件夹,运行“RSA签名验签工具.bat”(WINDOWS)或“RSA签名验签工具.command”(MAC_OSX)。
界面示例:
详细步骤:
1.根据开发语言选择密钥格式。
2.选择密钥长度,建议使用2048位。
3.点击 “生成密钥”,会自动生成商户应用公钥和应用私钥。
4.点击“打开密钥文件路径”,即可找到生成的公私钥。如图:
生成的私钥需妥善保管,避免遗失,不要泄露。应用私钥需填写到代码中供签名时使用。应用公钥需提供给支付宝账号管理者上传到支付宝开放平台。
除了使用支付宝提供的一键生成密钥工具外,也可以使用OpenSSL工具命令生成密钥。步骤如下:
除了使用支付宝提供的一键生成工具外,也可以使用OpenSSL工具(下载地址https://www.openssl.org/source/?spm=a219a.7629140.0.0.b0VRLV)命令生成密钥。
首先进入OpenSSL工具,输入以下命令。
1
2
3
4
|
OpenSSL> genrsa -out app_private_key.pem
1024
#生成私钥
OpenSSL> pkcs8 -topk8 -inform PEM -in app_private_key.pem -outform PEM -nocrypt -out app_private_key_pkcs8.pem #Java开发者需要将私钥转换成PKCS8格式
OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem #生成公钥
OpenSSL> exit #退出OpenSSL程序
|
经过以上步骤,开发者可以在当前文件夹中(OpenSSL运行文件夹),看到app_private_key.pem(开发者RSA私钥,非Java语言适用)、app_private_key_pkcs8.pem(pkcs8格式开发者RSA私钥,Java语言适用)和app_public_key.pem(开发者RSA公钥)3个文件。开发者将私钥保留,将公钥提交给支付宝配置到开发平台,用于验证签名。以下为私钥文件和公钥文件示例。
标准的私钥文件示例(PHP、.NET使用)
1
2
3
|
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC+L0rfjLl3neHleNMOsYTW8r0QXZ5RVb2p/vvY3fJNNugvJ7lo4+fdBz+LN4mDxTz4MTOhi5e2yeAqx+v3nKpNmPzC5LmDjhHZURhwbqFtIpZD51mOfno2c3MDwlrsVi6mTypbNu4uaQzw/TOpwufSLWF7k6p2pLoVmmqJzQiD0QIDAQABAoGAakB1risquv9D4zX7hCv9MTFwGyKSfpJOYhkIjwKAik7wrNeeqFEbisqv35FpjGq3Q1oJpGkem4pxaLVEyZOHONefZ9MGVChT/MNH5b0FJYWl392RZy8KCdq376Vt4gKVlABvaV1DkapL+nLh7LMo/bENudARsxD55IGObMU19lkCQQDwHmzWPMHfc3kdY6AqiLrOss+MVIAhQqZOHhDe0aW2gZtwiWeYK1wB/fRxJ5esk1sScOWgzvCN/oGJLhU3kipHAkEAysNoSdG2oWADxlIt4W9kUiiiqNgimHGMHPwp4JMxupHMTm7D9XtGUIiDijZxunHv3kvktNfWj3Yji0661zHVJwJBAM8TDf077F4NsVc9AXVs8N0sq3xzqwQD/HPFzfq6hdR8tVY5yRMb4X7+SX4EDPORKKsgnYcur5lk8MUi7r072iUCQQC8xQvUne+fcdpRyrR4StJlQvucogwjTKMbYRBDygXkIlTJOIorgudFlrKP/HwJDoY4uQNl8gQJb/1LdrKwIe7FAkBl0TNtfodGrDXBHwBgtN/t3pyi+sz7OpJdUklKE7zMSBuLd1E3O4JMzvWP9wEE7JDb+brjgK4/cxxUHUTkk592
-----END RSA PRIVATE KEY-----
|
PKCS8处理后的私钥文件示例(Java使用)
1
|
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAN0yqPkLXlnhM+2H/57aHsYHaHXazr9pFQun907TMvmbR04wHChVsKVgGUF1hC0FN9hfeYT5v2SXg1WJSg2tSgk7F29SpsF0I36oSLCIszxdu7ClO7c22mxEVuCjmYpJdqb6XweAZzv4Is661jXP4PdrCTHRdVTU5zR9xUByiLSVAgMBAAECgYEAhznORRonHylm9oKaygEsqQGkYdBXbnsOS6busLi6xA+iovEUdbAVIrTCG9t854z2HAgaISoRUKyztJoOtJfI1wJaQU+XL+U3JIh4jmNx/k5UzJijfvfpT7Cv3ueMtqyAGBJrkLvXjiS7O5ylaCGuB0Qz711bWGkRrVoosPM3N6ECQQD8hVQUgnHEVHZYtvFqfcoq2g/onPbSqyjdrRu35a7PvgDAZx69Mr/XggGNTgT3jJn7+2XmiGkHM1fd1Ob/3uAdAkEA4D7aE3ZgXG/PQqlm3VbE/+4MvNl8xhjqOkByBOY2ZFfWKhlRziLEPSSAh16xEJ79WgY9iti+guLRAMravGrs2QJBAOmKWYeaWKNNxiIoF7/4VDgrcpkcSf3uRB44UjFSn8kLnWBUPo6WV+x1FQBdjqRviZ4NFGIP+KqrJnFHzNgJhVUCQFzCAukMDV4PLfeQJSmna8PFz2UKva8fvTutTryyEYu+PauaX5laDjyQbc4RIEMU0Q29CRX3BA8WDYg7YPGRdTkCQQCG+pjU2FB17ZLuKRlKEdtXNV6zQFTmFc1TKhlsDTtCkWs/xwkoCfZKstuV3Uc5J4BNJDkQOGm38pDRPcUDUh2/
|
公钥文件示例
1
2
3
|
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQWiDVZ7XYxa4CQsZoB3n7bfxLDkeGKjyQPt2FUtm4TWX9OYrd523iw6UUqnQ+Evfw88JgRnhyXadp+vnPKP7unormYQAfsM/CxzrfMoVdtwSiGtIJB4pfyRXjA+KL8nIa2hdQy5nLfgPVGZN4WidfUY/QpkddCVXnZ4bAUaQjXQIDAQAB
-----END PUBLIC KEY-----
|
将公钥文件去除头尾、换行和空格,转成一行字符串。把该字符串提供给支付宝账号管理者,登录开放平台上传应用公钥并获取支付宝公钥。教程
例如转换前公钥pem文件格式:
1
2
3
|
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQWiDVZ7XYxa4CQsZoB3n7bfxLDkeGKjyQPt2FUtm4TWX9OYrd523iw6UUqnQ+Evfw88JgRnhyXadp+vnPKP7unormYQAfsM/CxzrfMoVdtwSiGtIJB4pfyRXjA+KL8nIa2hdQy5nLfgPVGZN4WidfUY/QpkddCVXnZ4bAUaQjXQIDAQAB
-----END PUBLIC KEY-----
|
转换后得到的字符串为:
1
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQWiDVZ7XYxa4CQsZoB3n7bfxLDkeGKjyQPt2FUtm4TWX9OYrd523iw6UUqnQ+Evfw88JgRnhyXadp+vnPKP7unormYQAfsM/CxzrfMoVdtwSiGtIJB4pfyRXjA+KL8nIa2hdQy5nLfgPVGZN4WidfUY/QpkddCVXnZ4bAUaQjXQIDAQAB
|
上一步获取到支付宝公钥,用于支付宝返回数据的验签。
对于支付宝公钥,看到的是一个字符串,如下:
1
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB
|
如果需要使用文件方式(如PHP/.NET版本)读取支付宝公钥,需要在头尾加入标示后保存至文件,文件内容如下:
1
2
3
|
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB
-----END PUBLIC KEY-----
|
SDK调用前需要进行初始化,代码示例如下:
1
|
AlipayClient alipayClient =
new
DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
|
关键参数说明:
配置参数 | 示例值解释 | 获取方式/示例值 |
---|---|---|
URL | 支付宝网关(固定) | https://openapi.alipay.com/gateway.do |
APP_ID | APPID即创建应用后生成 | 获取见上面创建应用并获取APPID |
APP_PRIVATE_KEY | 开发者应用私钥,由开发者自己生成 | 获取见上面配置密钥 |
FORMAT | 参数返回格式,只支持json | json(固定) |
CHARSET | 请求和签名使用的字符编码格式,支持GBK和UTF-8 | 开发者根据实际工程编码配置 |
ALIPAY_PUBLIC_KEY | 支付宝公钥,由支付宝生成 | 获取详见上面配置密钥 |
SIGN_TYPE | 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2 | RSA2 |
接下来,就可以用alipayClient来调用具体的API了。alipayClient只需要初始化一次,后续调用不同的API都可以使用同一个alipayClient对象。
应用开发完成后,请开发者自行进行验收并完成安全性检查。
//支付宝中验签的解释:
说一下简单支付流程:你提交等待支付的订单信息给支付宝,支付宝返回订单支付结果给你(这里暂时先不考虑服务器)。但是这里就有安全问题了,支付宝怎么知道你提交的订单信息商家的真实性?你又怎么知道支付宝返回的结果是支付宝官方操作而不是被篡改过的呢?
所以就有了安全验证一说,也就是私钥和公钥了。商家和支付宝都有一对公钥和私钥,支付宝的公钥提供给了每个商家(现在是统一的),商家的公钥在生成时也是应该提交到了支付宝的。私钥都是自己留着,不给别人。私钥用来数字签名,公钥用来对私钥签过名的信息做验证。
所以为了安全,你需要在发送订单信息的时候用你的私钥签名,发送给支付宝,支付宝用你的公钥去验证你的订单是否是本人。然后支付宝返回用支付宝私钥签名过的支付结果给你,你这个时候就需要用支付宝公钥去验证到底是不是真正的支付宝返回的信息。
/*
*生成订单信息及签名
*/
//将商品信息赋予AlixPayOrder的成员变量
Order* order = [Ordernew];
// NOTE: app_id设置
order.app_id = appID;
// NOTE: 支付接口名称
order.method =@"alipay.trade.app.pay";
// NOTE: 参数编码格式
order.charset =@"utf-8";
// NOTE: 当前时间点
NSDateFormatter* formatter = [NSDateFormatternew];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
order.timestamp = [formatterstringFromDate:[NSDatedate]];
// NOTE: 支付版本
order.version =@"1.0";
// NOTE: sign_type设置
order.sign_type =@"RSA";
// NOTE: 商品数据
order.biz_content = [BizContentnew];
order.biz_content.body =@"我是测试数据";
order.biz_content.subject =@"1";
order.biz_content.out_trade_no = [selfgenerateTradeNO];//订单ID(由商家自行制定)
order.biz_content.timeout_express =@"30m";//超时时间设置
order.biz_content.total_amount = [NSStringstringWithFormat:@"%.2f",0.01];//商品价格
//将商品信息拼接成字符串
NSString *orderInfo = [orderorderInfoEncoded:NO];
NSString *orderInfoEncoded = [orderorderInfoEncoded:YES];
NSLog(@"orderSpec = %@",orderInfo);
// NOTE: 获取私钥并将商户信息签名,外部商户的加签过程请务必放在服务端,防止公私钥数据泄露;
// 需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode
id<DataSigner> signer =CreateRSADataSigner(privateKey);//生成签名器
NSString *signedString = [signersignString:orderInfo];
// NOTE: 如果加签成功,则继续执行支付
if (signedString !=nil) {
//应用注册scheme,在AliSDKDemo-Info.plist定义URL types
NSString *appScheme =@"alisdkdemo";
// NOTE: 将签名成功字符串格式化为订单字符串,请严格按照该格式
NSString *orderString = [NSStringstringWithFormat:@"%@&sign=%@",
orderInfoEncoded, signedString];
// NOTE: 调用支付结果开始支付
[[AlipaySDKdefaultService]payOrder:orderStringfromScheme:appSchemecallback:^(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];
id dataVeri = CreateRSADataVerifier(@"public");//用支付宝公钥生成签名器
//支付宝公钥匙验证返回信息与签名 if ([dataVeri verifyString:orderString withSign:signedString]) { //验证签名成功,交易结果无篡改 NSLog(@"------------支付成功---------------"); } else { //验签错误 } } } else { //交易失败 } }]; }
}];
}
}
//跳转支付宝支付(安装了支付宝客户端的情况)时,支付完成之后重新回到本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) {
**验证方式同上面的网页支付**
}];
}
//这个是进程KILL掉之后也会调用,这个只是第一次授权回调,同时也会返回支付信息,
//处理支付宝客户端返回的url(在app被杀模式下,通过这个方法获取支付结果)。
[[AlipaySDK defaultService]processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) {
NSString * str = resultDic[@"result"];
NSLog(@"result = %@",str);
}];
return YES;}
不推荐客户端验证,应该由后台来做(后台做更安全)。