出現HTTP: 401 的時候的解析思路

###說在前面的話: 最近工做確實比較忙了一些, 畢竟是年初,不少事情都須要從新佈置, 一年之計在於春嘛; 這幾天,新來了一些小夥伴, 在他們接下來的一些工做中, 也發現了一些比較有意思的bug, 有些bug確屬不該該,不過也有些bug比較有意思, 有時間了,我會慢慢的整理一些發上來和你們分享, 今天先分享一個: HTTP: 401web

介紹: 什麼是HTTP: 401

時常作應用開發的夥伴們,估計你們對這個數字並不陌生, 畢竟只要你的應用須要申請服務器數據, 那麼不免會遇到它, 固然個人新來的這批小夥伴們也比較幸運的遇到了它, 嗯, 確實比較幸運, 由於bug出現,就是學習和進步的時候到了! 因此,我也就花了一些空餘時間來爲你們整理了一下;瀏覽器

###常見的HTTP:401錯誤碼:安全

401.1 - Logon failed. -登錄失敗
401.2 - Logon failed due to server configuration.-基於服務器配置的登錄失敗
401.3 - Unauthorized due to ACL on resource.-資源訪問控制列表返回未受權
401.4 - Authorization failed by filter.-服務器filter返回未受權
401.5 - Authorization failed by ISAPI/CGI application.-服務器ISAPI/CGI返回未受權

對於401,咱們能夠用一句話描述它:那就是 HTTP 401 錯誤 - 未受權: (Unauthorized) [絕大多數狀況下]服務器

簡單的來講: 就是你的Web服務器認爲,客戶端發送的 HTTP 數據流是正確的,但進入網址 (URL) 資源 , 須要用戶身份驗證 , 而相關信息 還沒有被提供, 或 已提供但沒有經過受權測試。 這就是一般所知的「 HTTP 基本驗證 」。 而需客戶端提供的驗證請求在 HTTP 協議中被定義爲 WWW – 驗證標頭字段 (WWW-Authenticate header field) 。網絡

那這個401錯誤碼 何時會產生呢?

####HTTP 循環中的 401錯誤app

任何客戶端 ( 好比瀏覽器,好比APP等等 ) ,都須要經過如下循環去向服務器請求數據:socket

1.首先從你的站點的 IP 名稱 ( 即您站點的網址-URL, 不帶起始的 ‘http://') 得到一個 IP 地址。這是由DNS來解析的;
2.接着, 打開一個 IP 套接字 (socket) 鏈接到該 IP 地址。
3.經過該套接字寫 HTTP 數據流。
4.從您的Web服務器接受響應的 HTTP 數據流。該數據流包括狀態編碼, 其值取決於 HTTP 協議 。 解析該數據流獲得 狀態編碼和其餘有用信息。

而401錯誤在容易在以上所述的最後一步產生,即當客戶端收到 HTTP 狀態編碼並識別其爲 ‘401‘ 時學習

例如我這裏作了一個測試: 你們看代碼 ,(因爲請求網絡服務器比較很差操做,因此,這個測試我用了本身電腦搭建的本地服務器;) 首先我給本身電腦的本地服務器(webDav)發送一個put請求, 準備上傳一張圖片到webDav服務器測試

NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/uploads/123.jpg"]; 
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];    
request.HTTPMethod =@"put";

而後獲取一張本地的圖片,網站

 //本地文件    
NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"head2.png"withExtension:nil];  
[[[NSURLSession sharedSession] uploadTaskWithRequest:request fromFile:
   fileUrl completionHandler:^(NSData *_Nullabledata, NSURLResponse *_Nullableresponse, NSError *_Nullableerror) {
        NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];    
}] resume];

接着開始執行:

這裏就會出現問題: 輸出結果: 輸出結果

經過輸出結果,能夠明顯的看獲得 服務器返回的是401, 由於咱們沒有受權, 那麼怎樣受權呢?

###解決 401 錯誤 – 情景一 : 有防護性的安全策略 一般狀況下 每一個Web服務器都有本身的方式管理用戶驗證。一般由該網站的網絡安全員(例如,系統管理員)決定哪些用戶被容許訪問該網址。 該人員使用 Web 服務器軟件來創建這些用戶的用戶名及其密碼。 所以, 若是您須要訪問某個網址(或您忘記了本身的用戶名和密碼), 只有該網站的網絡安全員能夠幫助您。任何安全問題需直接提交給他們。

若是你認爲該網站上的網頁 應該 是對任何互聯網用戶開放的, 那麼 401 信息就代表了一個更深層問題。 首先,您能夠經過一個瀏覽器檢查您的網址。 該瀏覽器應該運行在一臺您之前從未使用過, 也不包含任何有關您的信息的計算機上, 同時, 您還應避免使用您之前用過的身份驗證(密碼等)。 理想狀況是, 這一切應該經過一個徹底不一樣於任何您用過的互聯網鏈接(例如由不一樣的互聯網服務供應商- ISP 提供的撥號鏈接)。 簡而言之,您要模擬一個徹底陌生的人經過網上衝浪訪問您的網頁的狀況。

若是這種經過瀏覽器的檢查代表沒有受權問題,則多是您的 Web 服務器 ( 或周邊系統 ) 被設置爲不容許某種 HTTP 傳輸模式。 換句話說就是, 來自一個知名瀏覽器的 HTTP 通信是容許的, 但來自其餘系統的自動通信則被拒絕, 並生成 401 錯誤代碼。這是一種異常狀況, 可是也許代表您的 Web 服務器周圍 採起了很是具備防護性的安全策略。

好比: iOS9.0以後,就統一規定,對於http請求,只有通過蘋果承認的證書且是https:// 的,才能夠直接經過訪問,若是仍是http:// 或者,不是蘋果承認的證書的https,都是不能夠直接訪問的, 因此,一般狀況下,解決這類問題,咱們會事先在info.plist文件中作一些配置, 也就是咱們常說的ATS配置: 咱們能夠把下面這幾行配置添加到info.plist文件中, 首先用源代碼方式打開info.plist文件, 而後拷貝下面的幾行代碼: 以下:

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

解決 401 錯誤 – 情景二: 密碼,帳戶名錯誤

情景二: 須要提供密碼和帳號 當服務器須要驗證您的賬戶時,您能夠有選擇性地提供兩項信息

  1. 網站用戶名,
  2. 網站密碼。 固然只有當您的站點使用 HTTP 基本驗證時您才應該提供這些信息。 若是您不提供這些信息,服務器是通不過的,您也會獲得 401 錯誤。

就如最上面的put請求的代碼, 在服務器端,其實我是設定了須要密碼和帳號才能經過的, 因此,這種狀況下,咱們就須要提供帳號和密碼給服務器了,
固然,實際開發中,密碼和帳號是須要嚴格加密的,都是須要和服務器人員溝通一套很是保密的加密的方法的, 整個過程是比較複雜的, 不過因爲我這裏只是作一個演示, 那麼就不須要特別複雜了, 就簡單一點,說明一個思路便可:
這裏,我就手動來拼接一個帳號和密碼, 密碼加密就用最簡單的base64編碼;

假設咱們的帳號是admin,密碼也是123456, 那麼咱們怎樣來設定密碼呢? 首先咱們須要定義方法,來拼接密碼,並轉化爲base64編碼;

//定義一個方法: 獲取受權的字符串
- (NSString *)getAuth:(NSString *)name pwd:(NSString *)pwd {
    //拼字符串  admin:123456
    NSString *tmpStr = [NSString stringWithFormat:@"%@:%@",name,pwd];
    //base64編碼
    tmpStr = [self base64Encode:tmpStr];

    return [NSString stringWithFormat:@"Basic %@",tmpStr];
}

//base64編碼
- (NSString *)base64Encode:(NSString *)str  {
    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
    return [data base64EncodedStringWithOptions:0];
}

而後咱們在發送put請求的時候, 就同時提供受權

//上傳文件
- (void)uploadTask {
    NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/uploads/123.jpg"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"put";
    //設置帳號和密碼
    //Authorization: Basic YWRtaW46MTIzNDU2
    // admin:123456
    [request setValue:[self getAuth:@"admin" pwd:@"123456"] forHTTPHeaderField:@"Authorization"];
    
    //本地文件
    NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"head2.png" withExtension:nil];  
    [[[NSURLSession sharedSession] uploadTaskWithRequest:request fromFile:fileUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        
        NSLog(@"--%@",str);
        
    }] resume];
}

執行結果:

執行結果:

經過結果,咱們能夠看出, 已經上傳成功了, 也就是說,咱們順利的解決了401問題,

###總結解決bug的思路: 若是遇到401問題, 咱們解決的思路,能夠這樣來考慮:

  1. 優先考慮是不是須要驗證,也就是是否須要受權帳號和密碼信息;
  2. 若是是開放的服務器資源, 須要考慮的是是否有防護性的安全策略;

通常狀況下,都屬於這兩種緣由,

以上屬於我整理的,若有不足之處,望你們斧正! 感謝!!

相關文章
相關標籤/搜索