一、概述
AFNetworking 是 iOS 中常用的网络请求库,其使用也比较简单,以 POST 请求为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
NSDictionary *parameters = @{@"title": @"foo", @"body": @"bar", @"userId": @1};
[manager POST:@"https://www.lixkit.com/posts" parameters:parameters headers:nil progress:nil success:^(NSURLSessionDataTask *task, id responseObject) { NSLog(@"POST 请求成功,响应数据:%@", responseObject); } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"POST 请求失败,错误信息:%@", error); } ];
|
AFNetworking(4.0) 核心类可以按照下图进行分层:
各层职责:
AFHTTPSessionManager
- 继承自
AFURLSessionManager
,提供对外 API 处理常见的 HTTP 请求(如 GET
、POST
、PUT
、DELETE
等)
AFURLSessionManager
- 提供对
NSURLSession
的封装,基于 NSURLSession
提供了实际的 HTTP 请求实现
AFHTTPRequestSerializer
- 用于将请求参数序列化为适合 HTTP 请求体的格式,支持
JSON
、XML
、Property List
等格式的请求序列化
AFHTTPResponseSerializer
- 用于将 HTTP 响应数据反序列化为常见的数据结构,解析
JSON
、XML
、Property List
等格式的响应数据
AFNetworkReachabilityManager
AFSecurityPolicy
二、源码解读
1、AFHTTPSessionManager/AFURLSessionManager
以 POST
请求为例,其实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| - (nullable NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary <NSString *, NSString *> *)headers progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure { NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters headers:headers uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure]; [dataTask resume]; return dataTask; }
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method URLString:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary <NSString *, NSString *> *)headers uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure { NSError *serializationError = nil; NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError]; for (NSString *headerField in headers.keyEnumerator) { [request setValue:headers[headerField] forHTTPHeaderField:headerField]; } if (serializationError) { if (failure) { dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{ failure(nil, serializationError); }); } return nil; }
__block NSURLSessionDataTask *dataTask = nil; dataTask = [self dataTaskWithRequest:request uploadProgress:uploadProgress downloadProgress:downloadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { if (error) { if (failure) { failure(dataTask, error); } } else { if (success) { success(dataTask, responseObject); } } }];
return dataTask; }
|
根据上述逻辑可以看出 AFNetworking 是基于 NSURLSession
实现的网络请求,AFURLSessionManager
是 AFHTTPSessionManager
的父类,AFURLSessionManager
对 NSURLSession
及其任务(包括 NSURLSessionUploadTask
)进行了封装,并将原本通过 NSURLSessionDelegate
接收的回调改为了使用 block
回调的形式。
2、AFHTTPRequestSerializer
AFHTTPSessionManager
中持有了 AFHTTPRequestSerializer
的实例,在发起网络请求前可以配置 requestSerializer
参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
@end
|
AFHTTPRequestSerializer
负责将请求参数序列化为适合 HTTP 请求体的格式,它提供了对 HTTP 请求的高级封装,支持多种序列化格式和请求配置,例如:
1 2 3 4 5 6 7 8
| AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
[requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; [requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
requestSerializer.timeoutInterval = 30;
|
AFHTTPRequestSerializer
有两个子类:AFJSONRequestSerializer
、AFPropertyListRequestSerializer
,两个子类都实现了 AFURLRequestSerialization
协议。
AFURLRequestSerialization
协议中声明了如下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| @protocol AFURLRequestSerialization <NSObject, NSSecureCoding, NSCopying>
- (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(nullable id)parameters error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
@end
这个方法的主要功能是将指定的参数编码到一个新的 NSURLRequest 中,并返回这个新的 NSURLRequest。
以 AFJSONRequestSerializer 为例,其对该方法的实现如下: - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error { NSParameterAssert(request);
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { return [super requestBySerializingRequest:request withParameters:parameters error:error]; }
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { if (![request valueForHTTPHeaderField:field]) { [mutableRequest setValue:value forHTTPHeaderField:field]; } }];
if (parameters) { if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { [mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; }
if (![NSJSONSerialization isValidJSONObject:parameters]) { if (error) { NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"The `parameters` argument is not valid JSON.", @"AFNetworking", nil)}; *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; } return nil; }
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]; if (!jsonData) { return nil; } [mutableRequest setHTTPBody:jsonData]; }
return mutableRequest; }
|
可以看出,上述实现主要是将请求参数序列化为 JSON
格式,并将请求头的 Content-Type
设置为 application/json
。
开发时,可以直接使用 AFJSONRequestSerializer
和 AFPropertyListRequestSerializer
,也可以实现 AFURLRequestSerialization
协议自定义一个 requestSerializer
:
1 2 3 4
| AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
|
总结下 AFHTTPRequestSerializer
有两个子类的作用:
AFJSONRequestSerializer
- 将请求参数序列化为 JSON 格式
- 它会将请求头的
Content-Type
设置为 application/json
AFPropertyListRequestSerializer
- 将请求参数序列化为
Property List
格式
- 自动设置
Content-Type
为 application/x-plist
3、AFHTTPResponseSerializer
与 AFHTTPRequestSerializer
一样,AFHTTPSessionManager
中也持有了 AFHTTPResponseSerializer
的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
@end
|
上述 responseSerializer
在 NSURLSessionTaskDelegate
的 HTTP 请求完成的方法中调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #pragma mark - NSURLSessionTaskDelegate
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (error) {
} else { dispatch_async(url_session_manager_processing_queue(), ^{ NSError *serializationError = nil; responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
}); } }
|
可以看到,上述调用了 responseSerializer
的 responseObjectForResponse:data:error:
这个方法,这个方法实际上是 AFURLResponseSerialization
协议中声明的方法。
与 AFHTTPRequestSerializer
类似,AFHTTPResponseSerializer
也有多个子类,每个子类都实现了 AFURLResponseSerialization
协议中的如下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @protocol AFURLResponseSerialization <NSObject, NSSecureCoding, NSCopying>
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response data:(nullable NSData *)data error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
@end
|
简而言之,该方法的作用是将 HTTP 的 response
解析成指定的数据类型并返回。
以其中一个子类 AFJSONResponseSerializer
为例,其实现的该方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #pragma mark - AFURLResponseSerialization
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error { if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { return nil; } }
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]]; if (data.length == 0 || isSpace) { return nil; } NSError *serializationError = nil; id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
if (!responseObject) { if (error) { *error = AFErrorWithUnderlyingError(serializationError, *error); } return nil; } if (self.removesKeysWithNullValues) { return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions); }
return responseObject; }
|
上述主要逻辑是将服务器返回的原始数据(NSData
)解码为 JSON
对象(如 NSDictionary
或 NSArray
),并进行必要的验证和错误处理。
AFHTTPResponseSerializer
内置了如下几个子类:
AFJSONResponseSerializer
- 将服务器返回的 JSON 数据序列化为
NSDictionary
或 NSArray
对象
AFXMLParserResponseSerializer
- 将服务器返回的 XML 数据序列化为 NSXMLParser 对象
AFPropertyListResponseSerializer
- 将服务器返回的
Property List
数据序列化为 NSDictionary
或 NSArray
对象
AFImageResponseSerializer
- 将服务器返回的图像数据序列化为
UIImage
对象
AFCompoundResponseSerializer
- 允许组合多个响应序列化器,根据不同的
MIME
类型处理响应
也可以实现 AFURLResponseSerialization
自定义 responseSerializer
。
4、AFNetworkReachabilityManager
(1)实现方式
AFNetworkReachabilityManager
是 AFNetworking 实现的一个工具类,用于检测当前网络是否可达,以及网络连接类型的变化(如 WiFi 或蜂窝网络)。
主要功能如下:
- 监控网络状态变化:检测网络连接是否可达。
- 监听网络连接类型:区分 WiFi 和蜂窝网络。
- 提供回调接口:在网络状态变化时执行指定的回调。
AFNetworkReachabilityManager
使用示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
[reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { switch (status) { case AFNetworkReachabilityStatusNotReachable: NSLog(@"网络不可达"); break; case AFNetworkReachabilityStatusReachableViaWiFi: NSLog(@"通过 WiFi 连接"); break; case AFNetworkReachabilityStatusReachableViaWWAN: NSLog(@"通过蜂窝网络连接"); break; case AFNetworkReachabilityStatusUnknown: default: NSLog(@"未知网络状态"); break; } }];
[reachabilityManager startMonitoring];
|
AFNetworkReachabilityManager
基于系统的 SCNetworkReachability
API 实现,其 startMonitoring
、stopMonitoring
实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
- (void)startMonitoring { [self stopMonitoring];
if (!self.networkReachability) { return; }
__weak __typeof(self)weakSelf = self; AFNetworkReachabilityStatusCallback callback = ^(AFNetworkReachabilityStatus status) { __strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); } return strongSelf; };
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),^{ SCNetworkReachabilityFlags flags; if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) { AFPostReachabilityStatusChange(flags, callback); } }); }
- (void)stopMonitoring { if (!self.networkReachability) { return; }
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); }
|
(2)SCNetworkReachability
SCNetworkReachability
是苹果提供的一个系统级 API,用于检测网络连接状态和监控网络连接的变化。它是 System Configuration 框架的一部分,适用于 iOS 和 macOS 应用程序。
主要功能如下:
- 检测网络连接状态:判断当前网络是否可达。
- 监控网络状态变化:监听网络连接状态的变化,并在状态变化时触发回调。
SCNetworkReachability
使用示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <SystemConfiguration/SystemConfiguration.h>
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) { if (flags & kSCNetworkReachabilityFlagsReachable) { if (flags & kSCNetworkReachabilityFlagsIsWWAN) { printf("网络通过蜂窝网络连接\n"); } else { printf("网络通过 WiFi 连接\n"); } } else { printf("网络不可达\n"); } }
int main(int argc, const char * argv[]) { @autoreleasepool { SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, "www.apple.com");
SCNetworkReachabilityContext context = {0, NULL, NULL, NULL, NULL}; SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFRunLoopRun();
CFRelease(reachability); } return 0; }
|
SCNetworkReachability
主要基于系统的网络栈和通知机制,使用时需要将 SCNetworkReachability
引用添加到 RunLoop
中,以确保系统能够在网络状态变化时触发回调。
SCNetworkReachability
使用系统的网络栈来检测网络连接状态,包括是否有网络连接、连接类型(WiFi 或蜂窝网络)等。
网络栈是操作系统中负责网络通信的一组协议和软件模块的集合。它处理从应用层到物理层的所有网络通信任务,包括数据封装、路由、传输控制等。对于 SCNetworkReachability
来说,它主要依赖于网络栈中的 IP 层和链路层来检测网络连接状态。
SCNetworkReachability
主要通过两种方式检查网络连接状态:
- 通过发送网络探测请求(如 ICMP ping)
- 使用系统的路由表来确定目标主机或 IP 地址是否可达:查询路由表,查看是否存在到达目标主机或 IP 地址的有效路径。如果存在有效路径,则目标主机或 IP 地址被认为是可达的。
5、AFSecurityPolicy
AFSecurityPolicy
也是被 AFHTTPSessionManager
持有的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer; @property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer; @property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
@end
|
AFSecurityPolicy
主要负责验证服务器的证书,确保网络通信的安全性。通过自定义安全策略,开发者可以灵活地控制 SSL/TLS
连接的验证过程。
主要作用:
- 证书验证:验证服务器证书的有效性。
- 公钥验证:验证服务器的公钥。
- 支持自定义证书:允许使用自定义证书进行验证。
- 配置不同的验证模式:通过
SSL/TLS
连接中的证书链来验证服务器的身份,提供三种验证模式:不验证、验证证书、验证公钥。
AFSSLPinningModeNone
- 不进行 SSL Pinning 验证,只依赖系统默认的证书验证机制。
- 适用于不需要额外安全验证的场景。
AFSSLPinningModeCertificate
- 验证服务器提供的证书是否与本地预置的证书匹配。
- 适用于需要确保服务器证书与预期证书完全一致的场景。
AFSSLPinningModePublicKey
- 验证服务器提供的证书中的公钥是否与本地预置的公钥匹配。
- 适用于需要确保服务器公钥与预期公钥一致的场景。
使用 AFSecurityPolicy
自定义证书的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #import <AFNetworking/AFNetworking.h>
- (void)configureSecurityPolicy { NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"my_custom_certificate" ofType:@"cer"]; NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesDomainName = NO;
securityPolicy.pinnedCertificates = [NSSet setWithObject:certData];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.securityPolicy = securityPolicy;
[manager GET:@"https://lixkit.com" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask *task, id responseObject) { NSLog(@"请求成功: %@", responseObject); } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"请求失败: %@", error); }]; }
|
AFSecurityPolicy
主要实现源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
| @implementation AFSecurityPolicy
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle { NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]]; for (NSString *path in paths) { NSData *certificateData = [NSData dataWithContentsOfFile:path]; [certificates addObject:certificateData]; }
return [NSSet setWithSet:certificates]; }
+ (instancetype)defaultPolicy { AFSecurityPolicy *securityPolicy = [[self alloc] init]; securityPolicy.SSLPinningMode = AFSSLPinningModeNone;
return securityPolicy; }
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode { NSSet <NSData *> *defaultPinnedCertificates = [self certificatesInBundle:[NSBundle mainBundle]]; return [self policyWithPinningMode:pinningMode withPinnedCertificates:defaultPinnedCertificates]; }
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates { AFSecurityPolicy *securityPolicy = [[self alloc] init]; securityPolicy.SSLPinningMode = pinningMode;
[securityPolicy setPinnedCertificates:pinnedCertificates];
return securityPolicy; }
- (instancetype)init { self = [super init]; if (!self) { return nil; }
self.validatesDomainName = YES;
return self; }
- (void)setPinnedCertificates:(NSSet *)pinnedCertificates { _pinnedCertificates = pinnedCertificates;
if (self.pinnedCertificates) { NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]]; for (NSData *certificate in self.pinnedCertificates) { id publicKey = AFPublicKeyForCertificate(certificate); if (!publicKey) { continue; } [mutablePinnedPublicKeys addObject:publicKey]; } self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys]; } else { self.pinnedPublicKeys = nil; } }
#pragma mark -
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain { if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) { NSLog(@"为了验证自签名证书的域名,必须使用 pinning。"); return NO; }
NSMutableArray *policies = [NSMutableArray array]; if (self.validatesDomainName) { [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; } else { [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()]; }
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
if (self.SSLPinningMode == AFSSLPinningModeNone) { return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust); } else if (!self.allowInvalidCertificates && !AFServerTrustIsValid(serverTrust)) { return NO; }
switch (self.SSLPinningMode) { case AFSSLPinningModeCertificate: { NSMutableArray *pinnedCertificates = [NSMutableArray array]; for (NSData *certificateData in self.pinnedCertificates) { [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)]; } SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
if (!AFServerTrustIsValid(serverTrust)) { return NO; }
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust); for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) { if ([self.pinnedCertificates containsObject:trustChainCertificate]) { return YES; } } return NO; } case AFSSLPinningModePublicKey: { NSUInteger trustedPublicKeyCount = 0; NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
for (id trustChainPublicKey in publicKeys) { for (id pinnedPublicKey in self.pinnedPublicKeys) { if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) { trustedPublicKeyCount += 1; } } } return trustedPublicKeyCount > 0; } default: return NO; } return NO; }
@end
|
上述主要逻辑如下:
- 获取证书
certificatesInBundle:
方法从指定的 bundle
中获取所有的 .cer
证书,并返回证书数据的集合。
- 创建默认安全策略
defaultPolicy
方法创建一个默认的安全策略,不进行 SSL Pinning。
- 根据 Pinning 模式创建安全策略
policyWithPinningMode:
方法根据指定的 Pinning 模式创建安全策略,并使用默认的证书。
policyWithPinningMode:withPinnedCertificates:
方法根据指定的 Pinning 模式和证书集合创建安全策略。
- 初始化方法
init
方法初始化安全策略实例,并默认设置 validatesDomainName
为 YES。
validatesDomainName
属性决定了在验证服务器证书时,是否需要检查证书中的域名(Common Name 或 Subject Alternative Name)是否与请求的域名匹配。这种验证可以防止中间人攻击(MITM),确保服务器的身份是可信的。
- 设置自定义证书
setPinnedCertificates:
方法设置自定义证书,并提取证书中的公钥。
- 评估服务器信任
evaluateServerTrust:forDomain:
方法评估服务器的信任,根据不同的 Pinning 模式(AFSSLPinningModeNone
、AFSSLPinningModeCertificate
、AFSSLPinningModePublicKey
)进行相应的验证。