首页 文章

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

提问于
浏览
76

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

  • Web 服务器确定尽管请求包含 well-formed Authorization 标头,但标头中的凭据未成功进行身份验证。

  • Web 服务器返回 401 状态代码,并包含一个或多个列出支持的身份验证类型的 WWW-Authenticate 标头。

  • 浏览器检测到对 XMLHttpRequest 对象的调用的响应是 401,响应包含 WWW-Authenticate 标头。然后它会弹出一个身份验证对话框,再次询问用户名和密码。

这一切都很好,直到第 3 步。我不想弹出对话框,我想要在我的 AJAX 回调函数中处理 401 响应。 (例如,通过在登录 page.)上显示错误消息,我希望用户 re-enter 他们的用户名和密码,当然,但我希望他们看到我友好,安心的登录表单,而不是浏览器丑陋的默认身份验证对话框。

顺便说一句,我无法控制服务器,所以让它返回自定义状态代码(i.e.,401 以外的东西)不是一个选项。

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


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

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

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

Web broswer 设计师注意到:如果对话框本身只是 user-friendly,没有人会问如何抑制身份验证对话框。我正在登录表单的全部原因是我们的产品管理团队正确地认为浏览器的身份验证对话框很糟糕。

11 回答

  • 17

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

    • 也许 Flash 以不同的方式处理(我还没有尝试过),所以有一个 flash 电影使请求可能会有所帮助。

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

  • 46

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

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

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

  • 15

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

    • HTTP 状态为 4xx

    • 响应中存在WWW-Authenticate标头

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

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

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

  • 5

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

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

    从 IETF 关于 403 的文件:

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

  • 4

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

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

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

  • 2

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

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

  • 2

    在 Mozilla 中,将 XMLHttpRequest(文档)的 mozBackgroundRequest 参数设置为 true 会抑制这些对话框并导致请求完全失败。但是,我不知道 cross-browser 支持有多好(包括那些失败请求的错误信息的质量是否非常好 browsers.)

  • 2

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

  • 1

    我对 MVC 5 和 VPN 也有同样的问题,每当我们使用 VPN 在 DMZ 之外时,我们发现自己必须回答这个浏览器消息。使用.net 我只是使用处理错误的路由

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

    到目前为止,它已经起作用,因为家庭控制器下的索引操作验证了用户。如果登录失败,此操作中的视图具有登录控件,我使用该登录控件使用传递到目录服务的 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,并且'swallows'是基本的 auth 对话框。

    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
    }
    

    希望这能为您节省一些时间。

  • 0

    我正在使用 Node,Express 和 Passport,并且正在努力解决同样的问题。我通过将www-authenticate标头显式设置为空字符串来实现它。就我而言,它看起来像这样:

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

    我希望能帮助别人!

相关问题