如何禁止浏览器的身份验证对话框?

时间:2008-09-17 18:22:03

标签: javascript ajax http-authentication

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

  1. Web服务器确定虽然请求包含格式正确的Authorization标头,但标头中的凭据无法成功进行身份验证。
  2. Web服务器返回401状态代码,并包含一个或多个WWW-Authenticate标头,列出支持的身份验证类型。
  3. 浏览器检测到对XMLHttpRequest对象的调用的响应是401,响应包括WWW-Authenticate标头。然后它会弹出一个身份验证对话框,再次询问用户名和密码。
  4. 这一切都很好,直到第3步。我不想弹出对话框,我想要在我的AJAX回调函数中处理401响应。 (例如,通过在登录页面上显示错误消息。)我希望用户重新输入他们的用户名和密码,当然,但我希望他们看到我友好,安心的登录表单,而不是浏览器的丑陋,默认验证对话框。

    顺便说一下,我无法控制服务器,所以让它返回自定义状态代码(即401之外的其他东西)不是一种选择。

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


    修改
    作者提供的其他信息(9月18日):
    我应该补充一点,浏览器的身份验证对话框弹出的真正问题是它给用户提供的信息不足。

    用户刚刚通过登录页面上的表单输入了用户名和密码,他相信他已经正确输入了这些用户名和密码,并且他点击了提交按钮或按回车键。他的期望是,他将被带到下一页,或者可能被告知他输入的信息不正确,应该再试一次。但是,他会出现一个意外的对话框。

    该对话框未确认他只是 输入用户名和密码。它没有明确说明存在问题,他应该再试一次。相反,该对话框向用户显示隐藏信息,例如“网站说:' [realm] '。”其中 [realm] 是一个只有程序员才会喜欢的简短域名。

    Web broswer设计师注意到:如果对话框本身更加用户友好,没有人会问如何抑制身份验证对话框。我正在做登录表单的整个原因是我们的产品管理团队正确地认为浏览器的身份验证对话框很糟糕。

12 个答案:

答案 0 :(得分:46)

我在这里遇到了同样的问题,我公司的后端工程师实现了一种显然被认为是一种好习惯的行为:当一个URL调用返回401时,如果客户端设置了标题X-Requested-With: XMLHttpRequest ,服务器在其响应中删除www-authenticate标头。

副作用是不显示默认的身份验证弹出窗口。

确保您的API调用将X-Requested-With标头设置为XMLHttpRequest。如果是这样,除了根据这种良好做法改变服务器行为之外没有任何事情可做......

答案 1 :(得分:17)

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

  1. 也许Flash会以不同的方式处理(我还没有尝试过),因此使用Flash影片可能会有所帮助。

  2. 您可以为您在自己的服务器上访问的服务设置“proxie”,并让它稍微修改一下身份验证标头,以便浏览器无法识别它们。

答案 2 :(得分:14)

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

  1. HTTP状态为4xx
  2. WWW-Authenticate标题出现在回复
  3. 如果您可以控制HTTP响应,则可以从响应中删除WWW-Authenticate标头,浏览器不会弹出登录对话框。

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

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

答案 3 :(得分:5)

我意识到这个问题及其答案已经很久了。但是,我最终到了这里。也许其他人也会这样。

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

从IETF文件403:

接收不足的有效凭据的服务器    获取访问权应该响应403(禁止)状态代码

答案 4 :(得分:4)

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

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

第二行会阻止对话框....

答案 5 :(得分:2)

您使用什么服务器技术,是否有用于身份验证的特定产品?

由于浏览器只是在完成它的工作,我相信你必须改变服务器端的东西,不要返回401状态代码。这可以使用自定义身份验证表单来完成,只需在身份验证失败时再次返回表单。

答案 6 :(得分:2)

在Mozilla中,将XMLHttpRequest(docs)的mozBackgroundRequest参数设置为true会禁止这些对话框并导致请求完全失败。但是,我不知道跨浏览器支持有多好(包括那些失败请求的错误信息的质量是否在浏览器中非常好。)

答案 7 :(得分:2)

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

答案 8 :(得分: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");

虽然到目前为止这个工作正常,但我必须让你知道我还在测试它并且上面的代码没有理由运行它所以它被删除...测试目前包括尝试发现第二组代码更具用处的情况。同样,这是一项正在进行中的工作,但由于它可以提供一些帮助或者让你的大脑慢慢思考一些想法,我现在决定添加它......一旦完成所有测试,我将用最终结果更新它。

答案 9 :(得分:0)

对于那些未提及的C#,ActionAttribute返回400而不是401,并且&#39;吞下&#39;基本身份验证对话框。

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
}

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

答案 10 :(得分:0)

我正在使用Node,Express&amp;护照和正在努力解决同样的问题。我通过明确地将www-authenticate标头设置为空字符串来实现它。就我而言,它看起来像这样:

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

我希望能帮助别人!

答案 11 :(得分:0)

我最近在为三星 Tizen 智能电视开发 Web 应用程序时遇到了类似的情况。需要扫描整个本地网络,但很少有 IP 地址返回带有“www-authenticate”标头的“401 Unauthorized”响应。由于“基本”身份验证类型(https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication),它弹出浏览器身份验证弹出窗口,要求用户输入“用户名”和“密码”。

为了摆脱这种情况,对我有用的简单方法是为 Fetc Api Call (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) 设置 credentials: 'omit'。官方文档说:

要确保浏览器不在请求中包含凭据,请使用凭据:'omit'

fetch('https://example.com', {
  credentials: 'omit'
})