今天是除夕日,本應(yīng)打算出去逛一下呵扛,并感受一下春節(jié)氣氛的每庆;
但沒人約,也約不到人今穿,還是在家好好學習吧缤灵;
同時祝大家春節(jié)快樂,在新的一年工作順利蓝晒,步步高升腮出,bug越來越少??
切入正題,最近看了一下AFN的源碼芝薇,為了加深知識點的印象和防止以后遺忘胚嘲,還是決定寫一篇關(guān)于 AFSecurityPolicy 的內(nèi)容進行總結(jié)。
AFSecurityPolicy
:
主要作用就是驗證 HTTPS
請求的證書是否有效洛二,如果 APP
中有一些敏感信息或者涉及交易信息馋劈,一定要使用 HTTPS
來保證交易或者用戶信息的安全。
NSURLConnection
已經(jīng)封裝了https
連接的建立晾嘶、數(shù)據(jù)的加密解密功能妓雾,我們直接使用NSURLConnection
是可以訪問https
網(wǎng)站的,但NSURLConnection
并沒有驗證證書是否合法变擒,無法避免中間人攻擊君珠。要做到真正安全通訊,需要我們手動去驗證服務(wù)端返回的證書娇斑,AFSecurityPolicy
封裝了證書驗證的過程策添,讓用戶可以輕易使用,除了去系統(tǒng)信任CA機構(gòu)
列表驗證毫缆,還支持SSL Pinning
方式的驗證唯竹。使用方法:
把服務(wù)端證書(需要轉(zhuǎn)換成cer
格式)放到APP
項目資源里,AFSecurityPolicy
會自動尋找根目錄下所有cer
文件
// .crt --->.cer
// 證書 ---> 公鑰 ---> 隨機數(shù) 加密
// 項目本地導(dǎo)入 ---> 誰安裝誰就能獲取到這個證書
// 證書:proy.
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"https" ofType:@"cer"];
NSData *data = [NSData dataWithContentsOfFile:cerPath];
NSSet *cerSet = [NSSet setWithObject:data];
AFSecurityPolicy *security = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:cerSet];
// 默認配置
[AFSecurityPolicy defaultPolicy];
security.allowInvalidCertificates = YES;
security.validatesDomainName = NO;
NSString *urlstr = @"https://xxx.xxx.34.197:9000/users/abc";
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 不安全 -- 授權(quán)
manager.securityPolicy = security;
[manager GET:urlstr parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"success--%@",responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"fail--%@",error);
}];
AFSecurityPolicy
一. 屬性 介紹
AFSecurityPolicy.h 文件
//AFSecurityPolicy.h
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
//不使用固定證書(本地)驗證服務(wù)器苦丁。直接從客戶端系統(tǒng)中的受信任頒發(fā)機構(gòu) CA 列表中去驗證
AFSSLPinningModeNone,
// 代表會對服務(wù)器返回的證書中的PublicKey進行驗證浸颓,通過則通過,否則不通過
AFSSLPinningModePublicKey,
// 代表會對服務(wù)器返回的證書同本地證書全部進行校驗,通過則通過产上,否則不通過
AFSSLPinningModeCertificate,
};
@interface AFSecurityPolicy : NSObject <NSSecureCoding, NSCopying>
// 返回SSL Pinning的類型棵磷。默認的是AFSSLPinningModeNone。
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
/**
這個屬性保存著所有的可用做校驗的證書的集合晋涣。AFNetworking默認會搜索工程中所有.cer的證書文件仪媒。
如果想指定某些證書,可使用certificatesInBundle在目標路徑下加載證書谢鹊,
然后調(diào)用policyWithPinningMode:withPinnedCertificates創(chuàng)建一個本類對象算吩。
注意: 只要在證書集合中任何一個校驗通過,evaluateServerTrust:forDomain: 就會返回true佃扼,即通過校驗偎巢。
*/
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;
// 使用允許無效或過期的證書,默認是不允許兼耀。
@property (nonatomic, assign) BOOL allowInvalidCertificates;
// 是否驗證證書中的域名domain
@property (nonatomic, assign) BOOL validatesDomainName;
// 返回指定bundle中的證書压昼。如果使用AFNetworking的證書驗證 ,就必須實現(xiàn)此方法翠订,
并且使用policyWithPinningMode:withPinnedCertificates 方法來創(chuàng)建實例對象巢音。
+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;
/**
默認的實例對象,默認的認證設(shè)置為:
1. 不允許無效或過期的證書
2. 驗證domain名稱
3. 不對證書和公鑰進行驗證
*/
+ (instancetype)defaultPolicy;
// 創(chuàng)建默認實例
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;
// 根據(jù)指定的證書和pinningMode來創(chuàng)建實例
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;
// 校驗的關(guān)鍵方法 sessionmanager會調(diào)用
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(nullable NSString *)domain;
@end
二. 初始化以及設(shè)置
在使用 AFSecurityPolicy
驗證服務(wù)端是否受到信任之前尽超,要對其進行初始化官撼,使用初始化方法時,主要目的是設(shè)置驗證服務(wù)器是否受信任的方式似谁。
//AFSecurityPolicy.m
// 根據(jù)指定的SSL驗證模式創(chuàng)建實例
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
// 獲得APP下的所有證書 [self defaultPinnedCertificates]
return [self policyWithPinningMode:pinningMode withPinnedCertificates:[self defaultPinnedCertificates]];
}
// 根據(jù)SSL驗證模式和指定的證書集合創(chuàng)建實例
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates {
AFSecurityPolicy *securityPolicy = [[self alloc] init];
securityPolicy.SSLPinningMode = pinningMode;
// 設(shè)置證書集合 如果是默認的 已經(jīng)通過[self defaultPinnedCertificates]得到了
[securityPolicy setPinnedCertificates:pinnedCertificates];
// 公鑰的取出
return securityPolicy;
}
在調(diào)用 pinnedCertificates
的 setter
方法時傲绣,會從全部的證書中取出公鑰保存到 pinnedPublicKeys
屬性中。
// 此函數(shù)設(shè)置securityPolicy中的pinnedCertificates屬性
// 注意還將對應(yīng)的self.pinnedPublicKeys屬性也設(shè)置了巩踏,該屬性表示的是對應(yīng)證書的公鑰(與pinnedCertificates中的證書是一一對應(yīng)的)
- (void)setPinnedCertificates:(NSSet *)pinnedCertificates {
_pinnedCertificates = pinnedCertificates;
//獲取對應(yīng)公鑰集合
if (self.pinnedCertificates) {
//創(chuàng)建公鑰集合
NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]];
//從證書中拿到公鑰秃诵。
for (NSData *certificate in self.pinnedCertificates) {
// 取出合法的公鑰
// 傳輸 -- session -- 驗證當前所有的信息
id publicKey = AFPublicKeyForCertificate(certificate);
if (!publicKey) {
continue;
}
[mutablePinnedPublicKeys addObject:publicKey];
}
self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
} else {
self.pinnedPublicKeys = nil;
}
}
在這里調(diào)用了 AFPublicKeyForCertificate
對證書進行操作,返回一個公鑰塞琼。
三. 操作 SecTrustRef
static id AFPublicKeyForCertificate(NSData *certificate)
在該函數(shù)是返回單個證書的公鑰(所以傳入的參數(shù)是一個證書),函數(shù)代碼如下(含注釋):
static id AFPublicKeyForCertificate(NSData *certificate) {
id allowedPublicKey = nil;
SecCertificateRef allowedCertificate;
SecCertificateRef allowedCertificates[1];
CFArrayRef tempCertificates = nil;
SecPolicyRef policy = nil;
SecTrustRef allowedTrust = nil;
SecTrustResultType result;
// 1. 根據(jù)二進制的certificate生成SecCertificateRef類型的證書
// NSData *certificate 通過CoreFoundation (__bridge CFDataRef)轉(zhuǎn)換成 CFDataRef
allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
// 2.如果allowedCertificate為空菠净,則執(zhí)行標記_out后邊的代碼
__Require_Quiet(allowedCertificate != NULL, _out);
allowedCertificates[0] = allowedCertificate;
tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
// 新建policy為X.509
policy = SecPolicyCreateBasicX509();
//3. 創(chuàng)建SecTrustRef對象,如果出錯就跳到_out標記處
__Require_noErr_Quiet(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
// 4.校驗證書是否可信任的過程彪杉,這個不是異步的毅往。
__Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
// 5.在SecTrustRef對象中取出公鑰
// 公鑰是授信的,下面一行代碼就是為了證明這個公鑰是合法的
allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
// _out 用途 釋放各種 C 語言指針
_out:
if (allowedTrust) {
CFRelease(allowedTrust);
}
if (policy) {
CFRelease(policy);
}
if (tempCertificates) {
CFRelease(tempCertificates);
}
if (allowedCertificate) {
CFRelease(allowedCertificate);
}
/*
① NSData *certificate -> CFDataRef -> (SecCertificateCreateWithData) -> SecCertificateRef allowedCertificate
②判斷SecCertificateRef allowedCertificate 是不是空派近,如果為空攀唯,直接跳轉(zhuǎn)到后邊的代碼 即:_out
③SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust) -> 生成SecTrustRef allowedTrust
④SecTrustEvaluate(allowedTrust, &result) 校驗證書
⑤(__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust) -> 得到公鑰id allowedPublicKey
*/
return allowedPublicKey;
}
四. 驗證服務(wù)端是否受信
驗證服務(wù)端是否受信是通過- [AFSecurityPolicy evaluateServerTrust:forDomain:]
方法進行的。
SecTrustRef
:其實就是一個容器渴丸,裝了服務(wù)器端需要驗證的證書的基本信息侯嘀、公鑰等等另凌,不僅如此,它還可以裝一些評估策略戒幔,還有客戶端的錨點證書吠谢,這個客戶端的證書,可以用來和服務(wù)端的證書去匹配驗證的溪食。
每一個SecTrustRef
對象包含多個SecCertificateRef
和 SecPolicyRef
囊卜。其中 SecCertificateRef
可以使用 DER
進行表示。
domain:
服務(wù)器域名错沃,用于域名驗證
a. 根據(jù)severTrust
和domain
來檢查服務(wù)器端發(fā)來的證書是否可信
b. 其中SecTrustRef
是一個CoreFoundation
類型,用于對服務(wù)器端傳來的X.509
證書評估的
c. 而我們都知道雀瓢,數(shù)字證書的簽發(fā)機構(gòu)CA
枢析,在接收到申請者的資料后進行核對并確定信息的真實有效,然后就會制作一份符合X.509
標準的文件刃麸。證書中的證書內(nèi)容包含的持有者信息和公鑰等都是由申請者提供的醒叁,而數(shù)字簽名則是CA
機構(gòu)對證書內(nèi)容進行hash
加密后得到的,而這個數(shù)字簽名就是我們驗證證書是否是有可信CA
簽發(fā)的數(shù)據(jù)泊业。
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain
{
#1: 不能隱式地信任自己簽發(fā)的證書
#2: 設(shè)置 policy
#3: 驗證證書是否有效
#4: 根據(jù) SSLPinningMode 對服務(wù)端進行驗證
return NO;
}
1.不能隱式的信任自己簽發(fā)的證書
// domain - 域名驗證
if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
//如果想要實現(xiàn)自簽名的HTTPS訪問成功把沼,必須設(shè)置pinnedCertificates,且不能使用defaultPolicy
NSLog(@"In order to val idate a domain name for self signed certificates, you MUST use pinning.");
//不受信任吁伺,返回
return NO;
}
Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors). Instead, add your own (self-signed) CA certificate to the list of trusted anchors.
如果有服務(wù)器域名饮睬、設(shè)置了允許信任無效或者過期證書(自簽名證書)、需要驗證域名篮奄、沒有提供證書或者不驗證證書捆愁,返回NO
。后兩者和allowInvalidCertificates
為真的設(shè)置矛盾窟却,說明這次驗證是不安全的昼丑。
2.設(shè)置 policy
//用來裝驗證策略
NSMutableArray *policies = [NSMutableArray array];
//生成驗證策略。如果要驗證域名夸赫,就以域名為參數(shù)創(chuàng)建一個策略菩帝,否則創(chuàng)建默認的basicX509策略
if (self.validatesDomainName) {
// 如果需要驗證domain,那么就使用SecPolicyCreateSSL函數(shù)創(chuàng)建驗證策略茬腿,其中第一個參數(shù)為true表示為服務(wù)器證書驗證創(chuàng)建一個策略呼奢,第二個參數(shù)傳入domain,匹配主機名和證書上的主機名
//1.__bridge:CF和OC對象轉(zhuǎn)化時只涉及對象類型不涉及對象所有權(quán)的轉(zhuǎn)化
//2.__bridge_transfer:常用在講CF對象轉(zhuǎn)換成OC對象時滓彰,將CF對象的所有權(quán)交給OC對象控妻,此時ARC就能自動管理該內(nèi)存
//3.__bridge_retained:(與__bridge_transfer相反)常用在將OC對象轉(zhuǎn)換成CF對象時,將OC對象的所有權(quán)交給CF對象來管理
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
} else {
// 如果不需要驗證domain揭绑,就使用默認的BasicX509驗證策略
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
}
// 為serverTrust設(shè)置驗證策略弓候,用策略對serverTrust進行評估
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
3.驗證證書的有效性
//如果是AFSSLPinningModeNone(不做本地證書驗證郎哭,從客戶端系統(tǒng)中的受信任頒發(fā)機構(gòu) CA 列表中去驗證服務(wù)端返回的證書)
if (self.SSLPinningMode == AFSSLPinningModeNone) {
//不使用ssl pinning 但允許自建證書,直接返回YES菇存;否則進行第二個條件判斷夸研,去客戶端系統(tǒng)根證書里找是否有匹配的證書,驗證serverTrust是否可信依鸥,直接返回YES
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
} else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
//如果驗證無效AFServerTrustIsValid亥至,而且allowInvalidCertificates不允許自簽,返回NO
return NO;
}
4.根據(jù) SSLPinningMode
對服務(wù)器信任進行驗證
switch (self.SSLPinningMode) {
//上一部分已經(jīng)判斷過了贱迟,如果執(zhí)行到這里的話就返回NO
case AFSSLPinningModeNone:
default:
return NO;
//驗證證書類型
// 這個模式表示用證書綁定(SSL Pinning)方式驗證證書姐扮,需要客戶端保存有服務(wù)端的證書拷貝
// 注意客戶端保存的證書存放在self.pinnedCertificates中
case AFSSLPinningModeCertificate: {
...
}
//公鑰驗證 AFSSLPinningModePublicKey模式同樣是用證書綁定(SSL Pinning)方式驗證,
//客戶端要有服務(wù)端的證書拷貝衣吠,只是驗證時只驗證證書里的公鑰茶敏,不驗證證書的有效期等信息。
//只要公鑰是正確的缚俏,就能保證通信不會被竊聽惊搏,因為中間人沒有私鑰,無法解開通過公鑰加密的數(shù)據(jù)
case AFSSLPinningModePublicKey: {
...
}
}
AFSSLPinningModeNone
:直接返回 NO
AFSSLPinningModeCertificate
:
// 全部校驗(NSBundle .cer)
NSMutableArray *pinnedCertificates = [NSMutableArray array];
//把證書data忧换,用系統(tǒng)api轉(zhuǎn)成 SecCertificateRef 類型的數(shù)據(jù),SecCertificateCreateWithData函數(shù)對原先的pinnedCertificates做一些處理恬惯,保證返回的證書都是DER編碼的X.509證書
for (NSData *certificateData in self.pinnedCertificates) {
//cf arc brige:cf對象和oc對象轉(zhuǎn)化 __bridge_transfer:把cf對象轉(zhuǎn)化成oc對象
//brige retain:oc轉(zhuǎn)成cf對象
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
// 將pinnedCertificates設(shè)置成需要參與驗證的Anchor Certificate(錨點證書,通過SecTrustSetAnchorCertificates設(shè)置了參與校驗錨點證書之后亚茬,假如驗證的數(shù)字證書是這個錨點證書的子節(jié)點酪耳,即驗證的數(shù)字證書是由錨點證書對應(yīng)CA或子CA簽發(fā)的,或是該證書本身才写,則信任該證書)葡兑,具體就是調(diào)用SecTrustEvaluate來驗證
//serverTrust是服務(wù)器來的驗證,有需要被驗證的證書
// 把本地證書設(shè)置為根證書赞草,
// 合法 + 校驗 : 設(shè)置為根證書 --- 取
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
//評估指定證書和策略的信任度(由系統(tǒng)默認可信或者由用戶選擇可信)
if (!AFServerTrustIsValid(serverTrust)) {
return NO;
}
// obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
//注意讹堤,這個方法和我們之前的錨點證書沒關(guān)系了,是去從我們需要被驗證的服務(wù)端證書厨疙,去拿證書鏈洲守。
// 服務(wù)器端的證書鏈,注意此處返回的證書鏈順序是從葉節(jié)點到根節(jié)點
// 所有服務(wù)器返回的證書信息
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
//reverseObjectEnumerator逆序
// 倒序遍歷
//這里的證書鏈順序是從葉節(jié)點到根節(jié)點
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
//如果我們的證書中沾凄,有一個和它證書鏈中的證書匹配的梗醇,就返回YES
// 是否本地包含相同的data
if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
return YES;
}
}
//沒有匹配的
return NO;
}
AFSSLPinningModePublicKey
:
NSUInteger trustedPublicKeyCount = 0;
// 從serverTrust中取出服務(wù)器端傳過來的所有可用的證書,并依次得到相應(yīng)的公鑰
NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
//遍歷服務(wù)端公鑰
for (id trustChainPublicKey in publicKeys) {
//遍歷本地公鑰
for (id pinnedPublicKey in self.pinnedPublicKeys) {
//判斷如果相同 trustedPublicKeyCount+1
if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
trustedPublicKeyCount += 1;
}
}
}
return trustedPublicKeyCount > 0;
a.會從服務(wù)器信任中獲取公鑰
b.pinnedPublicKeys
中的公鑰與服務(wù)器信任中的公鑰相同的數(shù)量大于 0撒蟀,就會返回真
五.與 AFURLSessionManager 協(xié)作
- URLSession:didReceiveChallenge:completionHandler:
該代理方法會在下面兩種情況調(diào)用:
1.當服務(wù)器端要求客戶端提供證書時或者進行NTLM
認證(Windows NT LAN Manager
叙谨,微軟提出的WindowsNT
挑戰(zhàn)/響應(yīng)驗證機制)時,此方法允許你的app提供正確的挑戰(zhàn)證書保屯。
2.當某個session
使用SSL/TLS
協(xié)議手负,第一次和服務(wù)器端建立連接的時候涤垫,服務(wù)器會發(fā)送給iOS客戶端一個證書,此方法允許你的app驗證服務(wù)期端的證書鏈(certificate keychain
)
注:如果你沒有實現(xiàn)該方法竟终,該session
會調(diào)用其NSURLSessionTaskDelegate
的代理方法URLSession:task:didReceiveChallenge:completionHandler:
蝠猬。
這個方法其實就是做https
認證的⊥炒罚看看上面的內(nèi)容榆芦,大概能看明白這個方法做認證的步驟,我們還是如果有自定義的做認證的Block
喘鸟,則調(diào)用我們自定義的匆绣,否則去執(zhí)行默認的認證步驟,最后調(diào)用完成認證什黑。
服務(wù)端發(fā)起的一個驗證挑戰(zhàn),客戶端需要根據(jù)挑戰(zhàn)的類型提供相應(yīng)的挑戰(zhàn)憑證犬绒。當然,挑戰(zhàn)憑證不一定都是進行HTTPS
證書的信任,也可能是需要客戶端提供用戶密碼或者提供雙向驗證時的客戶端證書。當這個挑戰(zhàn)憑證被驗證通過時,請求便可以繼續(xù)順利進行
在代理協(xié)議- URLSession:didReceiveChallenge:completionHandler:
或者- URLSession:task:didReceiveChallenge:completionHandler:
代理方法被調(diào)用時會運行這段代碼:
// 1.判斷接收服務(wù)器挑戰(zhàn)的方法是否是信任證書
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
//只需要驗證服務(wù)端證書是否安全(即https的單向認證兑凿,這是AF默認處理的認證方式,其他的認證方式茵瘾,只能由我們自定義Block的實現(xiàn)
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
// 2.信任評估通過,就從受保護空間里面拿出證書,回調(diào)給服務(wù)器,告訴服務(wù),我信任你,你給我發(fā)送數(shù)據(jù)吧.
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
// 確定挑戰(zhàn)的方式
if (credential) {
//證書挑戰(zhàn)
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
//默認挑戰(zhàn)
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
//取消挑戰(zhàn)
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
//默認挑戰(zhàn)方式
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
NSURLAuthenticationChallenge
表示一個認證的挑戰(zhàn)礼华,提供了關(guān)于這次認證的全部信息。它有一個非常重要的屬性 protectionSpace
拗秘,這里保存了需要認證的保護空間, 每一個 NSURLProtectionSpace
對象都保存了主機地址圣絮,端口和認證方法等重要信息。
在上面的方法中雕旨,如果保護空間中的認證方法為 NSURLAuthenticationMethodServerTrust
扮匠,那么就會使用在上一小節(jié)中提到的方法- [AFSecurityPolicy evaluateServerTrust:forDomain:]
對保護空間中的 serverTrust
以及域名host
進行認證
根據(jù)認證的結(jié)果,會在 completionHandler
中傳入不同的disposition
和credential
參數(shù)凡涩。
鳴謝:林大鵬天地
參考:http://www.reibang.com/p/2137372396d2
本文章內(nèi)容純粹個人見解并僅用于分享交流棒搜,如有描述不當之處,歡迎指出與交流活箕,謝謝力麸!