說在前面的話:
最近工作確實比較忙了一些, 畢竟是年初,很多事情都需要重新布置, 一年之計在于春嘛;
這幾天,新來了一些小伙伴, 在他們接下來的一些工作中, 也發(fā)現(xiàn)了一些比較有意思的bug, 有些bug確屬不應該,不過也有些bug比較有意思, 有時間了,我會慢慢的整理一些發(fā)上來和大家分享, 今天先分享一個: HTTP: 401
介紹: 什么是HTTP: 401
時常做應用開發(fā)的伙伴們,估計大家對這個數(shù)字并不陌生, 畢竟只要你的應用需要申請服務器數(shù)據(jù), 那么難免會遇到它, 當然我的新來的這批小伙伴們也比較幸運的遇到了它, 嗯, 確實比較幸運, 因為bug出現(xiàn),就是學習和進步的時候到了!
所以,我也就花了一些空余時間來為大家整理了一下;
常見的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) [絕大多數(shù)情況下]
簡單的來說: 就是你的Web服務器認為戏羽,客戶端發(fā)送的 HTTP 數(shù)據(jù)流是正確的蜡歹,但進入網(wǎng)址 (URL) 資源 沪停, 需要用戶身份驗證 遮斥, 而相關信息 尚未被提供, 或 已提供但沒有通過授權測試录择。
這就是通常所知的“ HTTP 基本驗證 ”勺阐。
而需客戶端提供的驗證請求在 HTTP 協(xié)議中被定義為 WWW – 驗證標頭字段 (WWW-Authenticate header field) 绊谭。
那這個401錯誤碼 什么時候會產(chǎn)生呢?
HTTP 循環(huán)中的 401錯誤
任何客戶端 ( 比如瀏覽器,比如APP等等 ) 翻擒,都需要通過以下循環(huán)去向服務器請求數(shù)據(jù):
1.首先從你的站點的 IP 名稱 ( 即您站點的網(wǎng)址-URL, 不帶起始的 ‘http://') 獲得一個 IP 地址氓涣。這是由DNS來解析的;
2.接著, 打開一個 IP 套接字 (socket) 連接到該 IP 地址。
3.通過該套接字寫 HTTP 數(shù)據(jù)流陋气。
4.從您的Web服務器接受響應的 HTTP 數(shù)據(jù)流劳吠。該數(shù)據(jù)流包括狀態(tài)編碼, 其值取決于 HTTP 協(xié)議 巩趁。 解析該數(shù)據(jù)流得到 狀態(tài)編碼和其他有用信息痒玩。
而401錯誤在容易在以上所述的最后一步產(chǎn)生,即當客戶端收到 HTTP 狀態(tài)編碼并識別其為 ‘401‘ 時
例如我這里做了一個測試: 大家看代碼 ,(由于請求網(wǎng)絡服務器比較不好操作,所以,這個測試我用了自己電腦搭建的本地服務器;)
首先我給自己電腦的本地服務器(webDav)發(fā)送一個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];
接著開始執(zhí)行:
這里就會出現(xiàn)問題:
輸出結果:
通過輸出結果,可以明顯的看得到 服務器返回的是401, 因為我們沒有授權, 那么怎樣授權呢?
解決 401 錯誤 – 情景一 : 有防御性的安全策略
通常情況下
每個Web服務器都有自己的方式管理用戶驗證咖摹。通常由該網(wǎng)站的網(wǎng)絡安全員(例如严拒,系統(tǒng)管理員)決定哪些用戶被允許訪問該網(wǎng)址逆粹。 該人員使用 Web 服務器軟件來建立這些用戶的用戶名及其密碼。 因此草讶, 如果您需要訪問某個網(wǎng)址(或您忘記了自己的用戶名和密碼), 只有該網(wǎng)站的網(wǎng)絡安全員可以幫助您炉菲。任何安全問題需直接提交給他們堕战。
如果你認為該網(wǎng)站上的網(wǎng)頁 應該 是對任何互聯(lián)網(wǎng)用戶開放的, 那么 401 信息就表明了一個更深層問題拍霜。 首先嘱丢,您可以通過一個瀏覽器檢查您的網(wǎng)址。 該瀏覽器應該運行在一臺您以前從未使用過祠饺, 也不包含任何有關您的信息的計算機上越驻, 同時, 您還應避免使用您以前用過的身份驗證(密碼等)。 理想情況是伐谈, 這一切應該通過一個完全不同于任何您用過的互聯(lián)網(wǎng)連接(例如由不同的互聯(lián)網(wǎng)服務供應商- ISP 提供的撥號連接)烂完。 簡而言之,您要模擬一個完全陌生的人通過網(wǎng)上沖浪訪問您的網(wǎng)頁的情況诵棵。
如果這種通過瀏覽器的檢查表明沒有授權問題抠蚣,則可能是您的 Web 服務器 ( 或周邊系統(tǒng) ) 被設置為不允許某種 HTTP 傳輸模式。 換句話說就是履澳, 來自一個知名瀏覽器的 HTTP 通訊是允許的嘶窄, 但來自其他系統(tǒng)的自動通訊則被拒絕, 并生成 401 錯誤代碼距贷。這是一種異常情況柄冲, 但是也許表明您的 Web 服務器周圍 采取了非常具有防御性的安全策略。
比如: iOS9.0之后,就統(tǒng)一規(guī)定,對于http請求,只有經(jīng)過蘋果認可的證書且是https:// 的,才可以直接通過訪問,如果還是http:// 或者,不是蘋果認可的證書的https,都是不可以直接訪問的, 所以,通常情況下,解決這類問題,我們會事先在info.plist文件中做一些配置, 也就是我們常說的ATS配置: 我們可以把下面這幾行配置添加到info.plist文件中, 首先用源代碼方式打開info.plist文件, 然后拷貝下面的幾行代碼: 如下:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
解決 401 錯誤 – 情景二: 密碼,賬戶名錯誤
情景二: 需要提供密碼和賬號
當服務器需要驗證您的帳戶時忠蝗,您可以有選擇性地提供兩項信息
- 網(wǎng)站用戶名,
- 網(wǎng)站密碼现横。
當然只有當您的站點使用 HTTP 基本驗證時您才應該提供這些信息。 如果您不提供這些信息阁最,服務器是通不過的,您也會得到 401 錯誤戒祠。
就如最上面的put請求的代碼, 在服務器端,其實我是設定了需要密碼和賬號才能通過的,
所以,這種情況下,我們就需要提供賬號和密碼給服務器了,
當然,實際開發(fā)中,密碼和賬號是需要嚴格加密的,都是需要和服務器人員溝通一套非常保密的加密的方法的, 整個過程是比較復雜的,
不過由于我這里只是做一個演示, 那么就不需要特別復雜了, 就簡單一點,說明一個思路即可:
這里,我就手動來拼接一個賬號和密碼, 密碼加密就用最簡單的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];
}
然后我們在發(fā)送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];
}
執(zhí)行結果:
通過結果,我們可以看出, 已經(jīng)上傳成功了, 也就是說,我們順利的解決了401問題,
總結解決bug的思路:
如果遇到401問題, 我們解決的思路,可以這樣來考慮:
- 優(yōu)先考慮是否是需要驗證,也就是是否需要授權賬號和密碼信息;
- 如果是開放的服務器資源, 需要考慮的是是否有防御性的安全策略;
一般情況下,都屬于這兩種原因,
以上屬于我整理的,如有不足之處,望大家斧正! 感謝!!