如何隐藏浏览器的身份验证对话框?


85

我的Web应用程序有一个登录页面,该页面通过AJAX调用提交身份验证凭据。如果用户输入正确的用户名和密码,则一切正常,但如果不正确,则会发生以下情况:

  1. Web服务器确定尽管请求中包含格式正确的Authorization标头,但标头中的凭据未成功进行身份验证。
  2. Web服务器返回401状态代码,并包含一个或多个列出受支持的身份验证类型的WWW-Authenticate标头。
  3. 浏览器检测到对我对XMLHttpRequest对象的调用的响应是401,并且该响应包含WWW-Authenticate标头。然后,它会弹出一个身份验证对话框,再次询问用户名和密码。

直到步骤3为止,一切都很好。我不想弹出对话框,我想处理AJAX回调函数中的401响应。(例如,通过在登录页面上显示错误消息。)当然,我希望用户重新输入用户名和密码,但我希望他们看到我友好的,令人放心的登录表单,而不是浏览器的默认丑陋外观身份验证对话框。

顺便说一句,我无法控制服务器,因此让它返回自定义状态代码(即401以外的其他内容)不是一种选择。

有什么办法可以禁止身份验证对话框?特别是,我可以在Firefox 2或更高版本中取消“需要身份验证”对话框吗?有什么方法可以抑制IE 6及更高版本中的“连接到[主机]”对话框?


编辑
作者提供的其他信息(9月18日):
我应该补充一点,弹出的浏览器身份验证对话框的真正问题在于,它无法向用户提供足够的信息。

用户刚刚通过登录页面上的表单输入了用户名和密码,他认为自己已经正确输入了二者,并且单击了提交按钮或按Enter。他的期望是他将被带到下一页,或者被告知他输入的信息不正确,应重试。但是,相反,他看到一个意外的对话框。

对话是没有的,他只是一个事实确认没有输入用户名和密码。它没有明确指出存在问题,他应该重试。而是,对话框为用户提供了诸如“网站说:' [领域] '”之类的神秘信息。其中[realm]是只有程序员才能喜欢的简短领域名称。

Web浏览器设计者应注意:如果对话框本身只是更易于使用,则没人会问如何隐藏身份验证对话框。我填写登录表单的全部原因是我们的产品管理团队正确地认为浏览器的身份验证对话框很糟糕。


1
答案是没有好的答案。Marijn提出的破解措施已尽其所能。当然,如果可能的话,使用服务器和您的JavaScript理解的自定义身份验证,而不是浏览器可以理解,这也可以解决问题。
dgvid

我遇到过同样的问题,并在此处对stackoverflow的评论中找到了此链接(不是我的博客):Loudvchar.blogspot.ca/2010/11/…希望对您有所帮助。
gies0r

Answers:


17

我认为这是不可能的-如果您使用浏览器的HTTP客户端实现,它将始终弹出该对话框。我想到两个技巧:

  1. 也许Flash对此的处理方式有所不同(我还没有尝试过),所以让Flash电影发出请求可能会有所帮助。

  2. 您可以在自己的服务器上为要访问的服务设置一个“代理”,并对其进行一些修改,以使浏览器无法识别它们。


尽管我怀疑“代理”黑客会成功,但“不可能”似乎是正确的答案。
dgvid

@Stobor您发布的重复项的可接受答案实际上链接回该问题作为其答案!
8bitjunkie 2014年

3
@ 7SpecialGems好收获。我并不是说这是一个骗子,我链接了一个特定的答案(WWW-Authenticate答案),该答案在接受答案的四年后发布。尽管事后看来,我不记得为什么要看那个东西,或者我是如何测试它的。
Stobor 2014年

1
我尝试通过以下代码捕获未经授权的401错误:$ .ajaxSetup({statusCode:{401:function(){RedirectToLogin();}}}); 但是IE总是显示浏览器的身份验证对话框。如何在ASP.Net MVC 2中隐藏此对话框?
PaulP

就像已经说过的那样,@ PaulP需要一个代理,该代理将剥离其WWW-Authenticate标头的401状态代码响应或某种自定义服务器实现。
微粒

51

我在这里遇到了相同的问题,并且我公司的后端工程师实施了一种行为,这显然是一种好习惯:当对URL的调用返回401时,如果客户端设置了标头X-Requested-With: XMLHttpRequest,则服务器将www-authenticate标头丢弃在响应。

副作用是默认身份验证弹出窗口不会出现。

确保您的API调用的X-Requested-With标头设置为XMLHttpRequest。如果是这样,除了按照此良好做法更改服务器行为外,没有其他事情可做。


3
如果后端基于Java / Spring,则该DelegatingAuthenticationEntryPoint句柄将为您处理此行为。
Derek Slife

这次真是万分感谢。许多图书馆都采用了这种行为,包括Devise
josephnvu

1
任何想法如何在nginx中做到这一点?“当URL调用返回401时,如果客户端设置了标头X-Requested-With:XMLHttpRequest,则服务器将在其响应中删除www-authenticate标头。”
markmnl

18

同时满足以下两个条件时,浏览器会弹出登录提示:

  1. HTTP状态为4xx
  2. WWW-Authenticate 标头出现在响应中

如果您可以控制HTTP响应,则可以WWW-Authenticate从响应中删除标头,并且浏览器不会弹出登录对话框。

如果您无法控制响应,则可以设置代理以WWW-Authenticate从响应中过滤出标头。

据我所知(如果我错了,请随时纠正我),一旦浏览器收到WWW-Authenticate标头,就无法阻止登录提示。


好信息。关于有效的WWW-Authenticate标头值,请参阅stackoverflow.com/a/1748451/225217
Brice Roncace,

6

我意识到这个问题及其答案非常古老。但是,我到了这里。也许其他人也会。

如果您有权访问返回401的Web服务的代码。在这种情况下,只需将服务更改为返回403(禁止访问),而不是返回401。浏览器将不会提示输入凭据以响应403。403是未经授权使用特定资源的经过身份验证的用户的正确代码。这似乎是OP的情况。

从关于403的IETF文件中:

收到不足以获取访问权限的有效凭据的服务器应使用403(禁止)状态代码进行响应


4

在Mozilla中,创建XMLHttpRequest对象时,可以使用以下脚本来实现它:

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

第二行防止出现对话框。


1
在Firefox 2下,这似乎无能为力。在Firefox 3下,这会导致DOM安全错误,NS_ERROR_DOM_SECURITY_ERR代码
1000。– dgvid

2

您使用哪种服务器技术?您使用特定的产品进行身份验证吗?

由于浏览器仅在执行其工作,因此我相信您必须在服务器端进行更改,以不返回401状态代码。可以使用自定义身份验证表单来完成此操作,该表单在身份验证失败时会再次返回该表单。


2

在Mozilla领域中,将XMLHttpRequest(docs)的mozBackgroundRequest参数设置为true会禁止显示这些对话框并导致请求完全失败。但是,我不知道跨浏览器的支持程度如何(包括这些失败请求上的错误信息的质量在所有浏览器中是否都很好)。


moz-前缀表示不支持跨浏览器(除非您可以找到在其他每个浏览器中都可以使用的相似参数)。
Brilliand

2

jan.vdbergh是事实,如果您可以将服务器端的401更改为另一个状态代码,则浏览器将无法捕获并绘制弹出窗口。另一种解决方案是将WWW-Authenticate标头更改为另一个自定义标头。我不相信为什么不同的浏览器不能支持它,在几个版本的Firefox中,我们可以使用mozBackgroundRequest来执行xhr请求,但是在其他浏览器中呢?在这里,Chromium中与此问题有一个有趣的链接


1

对于MVC 5和VPN,我也有同样的问题,无论何时我们使用VPN在DMZ之外时,我们都会发现自己必须回答此浏览器消息。使用.net,我只使用以下方法处理错误的路由

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

到目前为止,它之所以有效,是因为家庭控制器下的Index操作可以验证用户。如果登录失败,此操作中的视图将具有登录控件,我使用该控件通过传递给Directory Services的LDAP查询来使用登录方式登录用户:

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

尽管到目前为止效果不错,但我必须让您知道我仍在对其进行测试,并且上面的代码没有理由运行,因此有可能将其删除...测试当前包括尝试发现第二组的情况代码的更多用途。再说一次,这是一项正在进行的工作,但是由于它可能对您有所帮助或使您的大脑有些想法,因此我决定立即添加它……在完成所有测试后,我将使用最终结果对其进行更新。


1

我正在使用Node,Express和Passport,并且遇到了同样的问题。我通过将www-authenticate标头显式设置为空字符串来使其工作。就我而言,它看起来像这样:

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

希望对您有所帮助!


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
}

希望这可以节省您一些时间。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.