AFNetworkReachabilityManager

参考此文章http://www.jianshu.com/p/727f08bb9878

1
2
3
4
5
6
    struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;

#endif
return [self managerForAddress:&address];
  • 本地的reachibility
1
2
3
4
5
6
+ (instancetype)managerForAddress:(const void *)address {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];

return manager;
}
  • 如果是监听的某个域名的reachibility
1
2
3
4
5
+ (instancetype)managerForDomain:(NSString *)domain {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
return manager;
}
  • 具体如何实现监听?
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
- (void)startMonitoring {
[self stopMonitoring];
if (!self.networkReachability) {
return;
}
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;

strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}

};
id networkReachability = self.networkReachability;
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};

SCNetworkReachabilitySetCallback((__bridge SCNetworkReachabilityRef)networkReachability, AFNetworkReachabilityCallback, &context);

SCNetworkReachabilityScheduleWithRunLoop((__bridge SCNetworkReachabilityRef)networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags((__bridge SCNetworkReachabilityRef)networkReachability, &flags)) {
AFPostReachabilityStatusChange(flags, callback);
}
});
}

##AFSecurityPolicy
在NSURLConnectionDelegate中,有一个func connection(NSURLConnection, willSendRequestFor: URLAuthenticationChallenge)这个方法,表示在收到服务器回调需要https的时候是佛需要认证。AFNetworking通过AFSecurityPolicy来设置认证规则。[AFSecurityPolicy evaluateServerTrust:forDomain:]通过这个方法来认证是否安全

http://piglikeyoung.com/2017/01/26/AFNetworking-AFSecurityPolicy-5/
http://draveness.me/afnetworking5.html
https://juejin.im/entry/590014d2ac502e0063c41310
https://wizardforcel.gitbooks.io/network-basic/content/0.html
数字证书原理(重要)(http://www.cnblogs.com/JeffreySun/archive/2010/06/24/1627247.html)

基本使用

1
2
3
4
5
6
以下三种方式作为认证证书的方式。
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
AFSSLPinningModeNone,
AFSSLPinningModePublicKey,
AFSSLPinningModeCertificate,
};
  • 在AFNetworkingSessionManager中可以设置SecurityPolicy,这样就可以对自己业务中不同的需求来设置不同的policy.如开发服务器使用自签名的证书只需要认证公钥就可以。
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
-(AFSecurityPolicy*)ticketSecurityPolicy {
// /先导入证书
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"12306" ofType:@"cer"];//证书的路径
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
NSSet *set = [NSSet setWithObject:certData];

AFSecurityPolicy *securityPolicy;
if (true) {
securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:set];
}else{
// AFSSLPinningModeCertificate 使用证书验证模式。下面这个方法会默认使用项目里面的所有证书
securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
}
// allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
// 如果是需要验证自建证书,需要设置为YES
securityPolicy.allowInvalidCertificates = YES;

//validatesDomainName 是否需要验证域名,默认为YES;
//假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。
//置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。
//如置为NO,建议自己添加对应域名的校验逻辑。
securityPolicy.validatesDomainName = NO;

return securityPolicy;
}

源码

因为这几个都不属于AFSecurityPolicy类的内容。所以提出来成了静态方法

  • AFServerTrustIsValid 调用系统方法来验证单个的serverTrust是否有效
  • AFPublicKeyForCertificate, 从证书里面取出公钥
  • AFCertificateTrustChainForServerTrust 获取serverTrust中证书链上的所有证书
  • AFPublicKeyTrustChainForServerTrust获取serverTrust证书链上的每个证书的公钥并返回

AFSecurityPolicy中的类和实例方法

  • certificatesInBundle提取bundle中所有的cer文件,变成NSData,返回到NSSet中
  • defaultPinnedCertificates 调用上面的方法返回当前bundle的证书
  • defaultPolicy 默认为SSLPinningModeNone
  • policyWithPinningMode:(AFSSLPinningMode)pinningMode 设置pinningMode并使用当前bundle下的证书
  • setPinnedCertificates 刚调用这个方法,实际上会把所有certificate的public key提取出来,放到pinnedPublicKeys这个set属性里面
  • (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain 这个里面AFSSLPinningModeCertificate 会从serverTrust提取trustChain,然后看pinnedCertificates里面是否包含trustChain里面的某一个证书。AFSSLPinningModePublicKey,则会从serverTrust里面提取chain里面的public key。然后与pinnedPublicKeys比较。如果有一个trust那就返回YES