2008-09-17 54 views
66

我的web應用程序有一個登錄頁面,通過AJAX調用提交認證憑證。如果用戶輸入正確的用戶名和密碼,一切都很好,但如果沒有,會發生以下情況:如何禁止瀏覽器的驗證對話框?

  1. 該網站服務器確定,雖然要求包括一個結構良好的Authorization頭,在頭的憑據做未成功驗證。
  2. Web服務器返回401狀態碼,幷包含一個或多個WWW-Authenticate標題,其中列出了支持的身份驗證類型。
  3. 瀏覽器檢測到我對XMLHttpRequest對象的調用的響應是401,響應中包含WWW-Authenticate標頭。然後彈出一個認證對話框,詢問用戶名和密碼。

這一切都很好,直到第3步。我不想彈出對話框,我想要在我的AJAX回調函數中處理401響應。 (例如,通過在登錄頁面顯示錯誤消息。)我希望用戶重新輸入他們的用戶名和密碼,當然,但我希望他們看到我友好,令人放心的登錄表單,而不是瀏覽器的醜陋,默認認證對話框。

順便提一句,我無法控制服務器,因此讓它返回一個自定義狀態代碼(即,除401以外的東西)不是一個選項。

有什麼辦法可以抑制認證對話框嗎?特別是,我能否在Firefox 2或更高版本中禁用「需要身份驗證」對話框?有什麼辦法可以在IE 6及更高版本中禁止連接到[主機]對話框?


編輯
從筆者(9月18日)的更多信息:
我要補充一點,與瀏覽器的身份驗證對話框彈出真正的問題是,它給信息不足以用戶。

用戶剛剛通過登錄頁面上的表單輸入了用戶名和密碼,他認爲他已經正確輸入了他們,並且他點擊了提交按鈕或回車。他的期望是他會被帶到下一頁,或者被告知他錯誤地輸入了他的信息,應該再試一次。但是,他卻出現了一個意外的對話框。

該對話框沒有確認他只是確實輸入了用戶名和密碼。它沒有明確說明存在問題,他應該再試一次。相反,對話框會向用戶顯示隱藏的信息,如「網站說:'[realm]'。」其中[realm]是一個只有程序員才能喜歡的短域名。

Web broswer設計師注意到:如果對話框本身更簡單易用,沒有人會問如何抑制認證對話框。 整個我之所以做登錄表單是因爲我們的產品管理團隊正確地認爲瀏覽器的認證對話框很糟糕。

+1

答案是沒有好的答案。 Marijn提出的黑客手段儘可能接近。當然,如果可能的話,使用服務器和您的JavaScript(而不是瀏覽器)理解的自定義身份驗證也可以實現。 – dgvid 2009-09-30 13:34:25

+0

我一直在同一個問題,並發現這個鏈接的評論在這裏stackoverflow(不是我的博客):http://loudvchar.blogspot.ca/2010/11/avoiding-browser-popup-for-401.html希望它能幫助你。 – gies0r 2013-05-13 18:02:35

回答

17

我不認爲這是可能的 - 如果您使用瀏覽器的HTTP客戶端實現,它會一直彈出該對話框。兩名黑客浮現在腦海中:

  1. 也許閃存不同的方式處理這個(我還沒有嘗試過),所以有一個flash動畫製作的要求可能會有幫助。

  2. 您可以爲您在自己的服務器上訪問的服務設置'proxie',並讓它稍微修改身份驗證標頭,以便瀏覽器不會識別它們。

+0

「不可能」看起來是正確的答案,儘管我懷疑「proxie」黑客可以做到這一點。 – dgvid 2009-09-30 13:35:51

+5

實際上是可能的:http://stackoverflow.com/a/19102200顯示如何。 – Stobor 2014-01-16 06:28:00

+0

@Stobor對於您發佈的副本,您接受的答案實際上與此問題有關,因爲它的答案是! – 8bitjunkie 2014-12-11 14:53:03

3

您使用的是哪種服務器技術?是否存在您用於身份驗證的特定產品?

由於瀏覽器只是做它的工作,我相信你必須改變服務器端的東西,不返回401狀態代碼。這可以通過使用自定義身份驗證表單來完成,這些表單在身份驗證失敗時會再次返回表單。

4

在Mozilla中,當您創建XMLHttpRequest對象,你可以用下面的腳本實現它:

xmlHttp=new XMLHttpRequest(); 
xmlHttp.mozBackgroundRequest = true; 
xmlHttp.open("GET",URL,true,USERNAME,PASSWORD); 
xmlHttp.send(null); 

第二行阻止對話框....

2

在Mozilla的土地,將XMLHttpRequest(docs)的mozBackgroundRequest參數設置爲true會抑制這些對話框並導致請求失敗。但是,我不知道跨瀏覽器支持有多好(包括那些失敗請求上的錯誤信息的質量在瀏覽器中是否非常好)。

2

jan.vdbergh有事實,如果您可以更改服務器端的401爲另一個狀態碼,瀏覽器將無法捕捉並繪製彈出窗口。 另一個解決方案可能是更改另一個自定義標頭的WWW-Authenticate標頭。我不相信爲什麼不同的瀏覽器不支持它,在Firefox的幾個版本中,我們可以用mozBackgroundRequest做xhr請求,但在其他瀏覽器中?在這裏,Chromium中有一個有趣的link這個問題。

38

我在這裏遇到了同樣的問題,我公司的後臺工程師實施了一種顯然被認爲是良好實踐的行爲:當對URL的調用返回401時,如果客戶端已設置標頭X-Requested-With: XMLHttpRequest,在其響應中丟棄www-authenticate標題。

副作用是不顯示默認身份驗證彈出窗口。

確保您的API調用的X-Requested-With標頭設置爲XMLHttpRequest。如果是的話有什麼不同之處根據這個好習慣改變服務器的行爲做...

12

瀏覽器彈出時,以下兩個條件都滿足的登錄提示:

  1. HTTP狀態爲4XX
  2. WWW-Authenticate頭存在於響應

如果可以控制HTTP響應,則可以刪除該響應的WWW-Authenticate報頭,並且瀏覽器不會彈出登錄對話框。

如果您無法控制響應,則可以設置代理以從響應中篩選出WWW-Authenticate標頭。

據我所知(如果我錯了,隨時糾正我),一旦瀏覽器收到WWW-Authenticate標題,就無法阻止登錄提示。

1

我與MVC 5和VPN有同樣的問題,當我們在使用VPN的DMZ之外時,我們發現自己不得不回答這個瀏覽器消息。使用.NET,我只是用

<customErrors defaultRedirect="~/Error" > 
    <error statusCode="401" redirect="~/Index"/> 
</customErrors> 

迄今爲止它一直因爲根據家庭控制器Index操作驗證用戶處理錯誤的路由。在這個動作來看,如果登錄不成功,有我用它來記錄用戶在使用傳遞到目錄服務使用LDAP查詢登錄控件:

 DirectoryEntry entry = new DirectoryEntry("LDAP://OurDomain"); 
     DirectorySearcher Dsearch = new DirectorySearcher(entry); 
     Dsearch.Filter = "(SAMAccountName=" + UserID + ")"; 
     Dsearch.PropertiesToLoad.Add("cn"); 

雖然這一直很好迄今爲止,我必須讓你知道我還在測試它,上面的代碼沒有理由運行,所以它可能會被刪除......測試目前包括試圖發現第二組代碼是更多的使用情況。再一次,這是一項正在進行的工作,但是由於它可能會有一些幫助,或者爲了某些想法而讓大腦慢跑,所以我決定現在添加它......我將在所有測試完成後用最終結果更新它。

0

對於那些不在C#的人,這裏的ActionAttribute返回400而不是401和'吞嚥'基本身份驗證對話框。

public class NoBasicAuthDialogAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     base.HandleUnauthorizedRequest(filterContext); 
     filterContext.Result = new HttpStatusCodeResult(400); 
    } 
} 

使用類似以下內容:

[NoBasicAuthDialogAuthorize(Roles = "A-Team")] 
public ActionResult CarType() 
{ 
// your code goes here 
} 

希望這可以節省一些時間。

5

我意識到這個問題及其答案是非常古老的。但是,我最終在這裏。也許別人也會。

如果您有權訪問正在返回401的Web服務的代碼,只需將服務更改爲在此情況下返回403(禁止訪問),而不是401.瀏覽器將不會提示輸入憑據以響應403 403是未經授權用於特定資源的經過身份驗證的用戶的正確代碼。這似乎是OP的情況。

從上403的IETF文檔:

,其接收不足以 增益訪問應該與403(禁止)狀態碼

0

我使用的迴應有效憑據的服務器節點,快遞&護照,並在同一問題掙扎。我通過明確地將www-authenticate頭設置爲空字符串來實現它。在我的情況下,它看起來像這樣:

(err, req, res, next) => { 
    if (err) { 
    res._headers['www-authenticate'] = '' 
    return res.json(err) 
    } 
} 

我希望能幫助別人!

相關問題