前言
1.接入微信支付前,需要申请应用的appid,这将用于获取用户在该appid下的openid
2.需要一个微信商户号,用于企业微信支付,应用的appid需要绑定到这个微信商户上。
3.完成这些操作后,再去微信商户后台下载API证书,API证书将用于接口访问时的验证,一般微信不建议我们将API证书放在客户端,这样安全性得不到保证,这里只是在客户端完成微信支付过程,商业用户需要将证书安装到自主服务器上。
证书问题
1.需要将下载下来的cer证书拖入xcode工程中
2.post请求微信接口时,微信接口需要我们进行证书的单向认证
3.认证完毕,即可收到对应响应
4.详细过程请按照微信官方文档步骤来
请求代码
NSMutableURLRequest *request=[[NSMutableURLRequest alloc]init];
[request setURL:[NSURL URLWithString:url]];
[request setHTTPMethod:@"POST"];
NSString *contentType=[NSString stringWithFormat:@"text/xml"];
[request addValue:contentType forHTTPHeaderField:@"Content-Type"];
NSMutableData *postBody=[NSMutableData data];
[postBody appendData:[[NSString stringWithFormat:
@"<xml><mch_appid>%@</mch_appid><mchid>%@</mchid><nonce_str>%@</nonce_str><partner_trade_no>%@</partner_trade_no><openid>%@</openid><check_name>%@</check_name><amount>%d</amount><desc>%@</desc><sign>%@</sign></xml>",self.mch_appid,self.mchid,self.nonce_str,self.partner_trade_no,self.openid,self.check_name,self.amount,self.desc,self.sign] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postBody];
NSString *bodyStr=[[NSString alloc]initWithData:postBody encoding:NSUTF8StringEncoding];
NSLog(@"********提交表单信息 post body: %@",bodyStr);
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
//config.TLSMaximumSupportedProtocol = kTLSProtocol1;
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//NSURLSession *session=[NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"返回的数据 data:%@",data);
// NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
if(error)
{ NSLog(@"error:%@",error.description);
return;
}
GDataXMLDocument *document=[[GDataXMLDocument alloc]initWithData:data options:kNilOptions error:nil];
GDataXMLElement *root=document.rootElement;
NSArray *arr1=root.children;
Boolean returnCode=false;
Boolean resultCode=false;
NSString *err=nil;
for (int i=0; i<[arr1 count]; i++) {
GDataXMLElement *ele=[arr1 objectAtIndex:i];
// ele
NSLog(@"**************xml name:%@ value:%@ ",[ele name],[ele stringValue]);
if([[ele name]isEqualToString:@"return_code"]&&[[ele stringValue] isEqualToString: @"SUCCESS"])
{
returnCode=true;
}
if([[ele name]isEqualToString:@"result_code"]&&[[ele stringValue]isEqualToString: @"SUCCESS"])
{
resultCode=true;
}
if([[ele name]isEqualToString:@"err_code"])
{
err=[ele stringValue];
}
}
if(returnCode&&resultCode)
{
[[GDTAppDelegate shareInstance]paySuccess];
NSDictionary * para = [NSDictionary dictionaryWithObjectsAndKeys:@"openid",[GDTAppDelegate shareInstance].openid,@"amount",[GDTAppDelegate shareInstance].amount, nil];
[GDTAppDelegate payAction:@"withdrawal" attributes:para];
}
else
{
[[GDTAppDelegate shareInstance]payFail:err];
}
}];
[task resume];
证书验证代码:
NSURLCredential *secureCredential;
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
NSLog(@"证书认证");
NSLog(@"didReceiveChallenge: %@", challenge.protectionSpace.authenticationMethod);
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) {
NSLog(@"challenged for client certificate");
NSString *sslCertName = @"apiclient_cert";
NSString *path2 = [[NSBundle mainBundle] pathForResource:sslCertName ofType:@"p12"];
NSData *p12data = [NSData dataWithContentsOfFile:path2];
CFDataRef inP12data = (__bridge CFDataRef) p12data;
SecIdentityRef myIdentity;
SecTrustRef myTrust;
extractIdentityAndTrust(inP12data, &myIdentity, &myTrust);
SecCertificateRef myCertificate;
SecIdentityCopyCertificate(myIdentity, &myCertificate);
const void *certs[] = {myCertificate};
CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL);
CFRelease(myCertificate);
secureCredential = [NSURLCredential credentialWithIdentity:myIdentity
certificates:(__bridge NSArray *) certsArray
persistence:NSURLCredentialPersistencePermanent];
CFRelease(certsArray);
[[challenge sender] useCredential:secureCredential forAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeUseCredential, secureCredential);
}
else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSLog(@"challenged for server trust");
[challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]
forAuthenticationChallenge: challenge];
completionHandler(NSURLSessionAuthChallengeUseCredential,
[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
} else {
NSLog(@"other challenge");
if ([challenge previousFailureCount] == 0) {
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
} else {
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,nil);
}
}
}
OSStatus extractIdentityAndTrust(CFDataRef inP12data, SecIdentityRef *identity, SecTrustRef *trust)
{
OSStatus securityError = errSecSuccess;
CFStringRef password = CFSTR("1577168641");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import(inP12data, options, &items);
if (securityError == 0) {
CFDictionaryRef myIdentityAndTrust = (CFDictionaryRef)CFArrayGetValueAtIndex(items, 0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
*identity = (SecIdentityRef)tempIdentity;
const void *tempTrust = NULL;
tempTrust = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
*trust = (SecTrustRef)tempTrust;
}
if (options) {
CFRelease(options);
}
return securityError;
}