AFN 中的 AFSecurityPolicy

今天是除夕日,本應(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)用 pinnedCertificatessetter 方法時傲绣,會從全部的證書中取出公鑰保存到 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對象包含多個SecCertificateRefSecPolicyRef囊卜。其中 SecCertificateRef 可以使用 DER 進行表示。
domain:服務(wù)器域名错沃,用于域名驗證

a. 根據(jù)severTrustdomain來檢查服務(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 中傳入不同的dispositioncredential參數(shù)凡涩。

鳴謝:林大鵬天地
參考:http://www.reibang.com/p/2137372396d2
本文章內(nèi)容純粹個人見解并僅用于分享交流棒搜,如有描述不當之處,歡迎指出與交流活箕,謝謝力麸!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市育韩,隨后出現(xiàn)的幾起案子克蚂,更是在濱河造成了極大的恐慌,老刑警劉巖筋讨,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埃叭,死亡現(xiàn)場離奇詭異,居然都是意外死亡悉罕,警方通過查閱死者的電腦和手機赤屋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門立镶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人益缎,你說我怎么就攤上這事谜慌。” “怎么了莺奔?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵欣范,是天一觀的道長。 經(jīng)常有香客問我令哟,道長恼琼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任屏富,我火速辦了婚禮晴竞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狠半。我一直安慰自己噩死,他們只是感情好,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布神年。 她就那樣靜靜地躺著已维,像睡著了一般。 火紅的嫁衣襯著肌膚如雪已日。 梳的紋絲不亂的頭發(fā)上垛耳,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音飘千,去河邊找鬼堂鲜。 笑死,一個胖子當著我的面吹牛护奈,可吹牛的內(nèi)容都是我干的缔莲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼逆济,長吁一口氣:“原來是場噩夢啊……” “哼酌予!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起奖慌,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤抛虫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后简僧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體建椰,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年岛马,在試婚紗的時候發(fā)現(xiàn)自己被綠了棉姐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屠列。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖伞矩,靈堂內(nèi)的尸體忽然破棺而出笛洛,到底是詐尸還是另有隱情,我是刑警寧澤乃坤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布苛让,位于F島的核電站,受9級特大地震影響湿诊,放射性物質(zhì)發(fā)生泄漏狱杰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一厅须、第九天 我趴在偏房一處隱蔽的房頂上張望仿畸。 院中可真熱鬧,春花似錦朗和、人聲如沸错沽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甥捺。三九已至,卻和暖如春镀层,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背皿曲。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工唱逢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屋休。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓坞古,卻偏偏與公主長得像,于是被迫代替她去往敵國和親劫樟。 傳聞我的和親對象是個殘疾皇子痪枫,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容