即使苹果已经推迟ATS,但是也是早晚的事,此次就根据项目记录项目中是怎么支持https自建证书的
-
后台给到的证书是.crt格式的,但是项目需要的是der格式的(AFN3.0以上支持的是.der,3.0以下支持的是.cer)
转.der采用的命令行是:
openssl x509 -in /Users/nikkilin/Desktop/server.crt -out /Users/nikkilin/Desktop/server.der -outform DER
转.cer采用的命令行是:
openssl x509 -in /Users/nikkilin/Desktop/server.crt -out /Users/nikkilin/Desktop/server.cer -outform DER
- 接着将der证书拉入项目中
- 修改AFN网络请求工具类
+ (instancetype)sharedTools {
static NetworkTools *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [NetworkTools new];
[instance initSessionManager];
});
return instance;
}
- (void)initSessionManager{
_sessionManager = [AFHTTPSessionManager manager];
_sessionManager.requestSerializer.timeoutInterval = 15;
_sessionManager.requestSerializer.cachePolicy = NSURLRequestUseProtocolCachePolicy;
_sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/plain", @"*/*", nil];
AFImageDownloader *imageDownloader = [AFImageDownloader defaultInstance];
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:nil];
sessionManager.responseSerializer = [AFImageResponseSerializer serializer];
imageDownloader.sessionManager = sessionManager;
[self setSecurityPolicyWithManager:_sessionManager];
[self setSecurityPolicyWithManager:sessionManager];
[UIButton setSharedImageDownloader:imageDownloader];
}
-(void) setSecurityPolicyWithManager:(AFHTTPSessionManager *)manager
{
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
policy.allowInvalidCertificates = YES;// 是否允许自建证书或无效证书
policy.validatesDomainName = NO;
manager.securityPolicy = policy;
__weak AFHTTPSessionManager *weakManager = manager;
[manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession * _Nonnull session, NSURLAuthenticationChallenge * _Nonnull challenge, NSURLCredential *__autoreleasing _Nullable * _Nullable credential) {
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];
NSData *caData = [NSData dataWithContentsOfFile:cerPath];
weakManager.securityPolicy.pinnedCertificates = [NSSet setWithObject:caData];
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caData);
NSArray *caArray = @[(__bridge id)(caRef)];
OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
SecTrustSetAnchorCertificatesOnly(serverTrust,NO);
if (errSecSuccess == status) {
NSCAssert(YES, @"SecTrustSetAnchorCertificates failed");
}
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([weakManager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
//创建质询证书
NSURLCredential * credential = [NSURLCredential credentialForTrust:serverTrust];
if (credential) {
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
//取消质询
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
}
return disposition;
}];
}
- 接着常用的第三方SDWebImage就加载不了https的图片了,简单粗暴的办法就是
使用sd的这个方法,忽略证书,options设置SDWebImageAllowInvalidSSLCertificates
[self.imageV sd_setImageWithURL:[NSURL URLWithString:item.photo_source] placeholderImage:nil options:SDWebImageAllowInvalidSSLCertificates];
- 如果嫌每个地方都要添加options麻烦,那么可以给SDWebImage添加一个Category
@implementation SDWebImageDownloader (CXXSecurityValidate)
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"dev_merchant" ofType:@"cer"];
NSData *caData = [NSData dataWithContentsOfFile:cerPath];
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caData);
NSArray *caArray = @[(__bridge id)(caRef)];
OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
SecTrustSetAnchorCertificatesOnly(serverTrust,NO);
if (errSecSuccess == status) {
NSCAssert(YES, @"SecTrustSetAnchorCertificates failed");
}
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
NSURLCredential * credential = [NSURLCredential credentialForTrust:serverTrust];
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([[NetworkTools sharedTools].sessionManager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
if (credential) {
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
//取消质询
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
}
if (completionHandler) {
completionHandler(disposition, credential);
}
}
@end