24

我希望用户能够通过 HTTP Basic 身份验证模式登录。

问题是我还希望他们能够再次注销 - 奇怪的是浏览器似乎不支持这一点。

这被认为是一种社交黑客风险 - 用户将他们的机器解锁并打开他们的浏览器,其他人可以轻松地以他们的身份访问该网站。请注意,仅关闭浏览器选项卡不足以重置令牌,因此用户可能很容易错过。

所以我想出了一个解决方法,但它完全是一个难题:

1)将它们重定向到注销页面

2) 在该页面上触发一个脚本以 ajax 加载另一个具有虚拟凭据的页面:

$j.ajax({
    url: '<%:Url.Action("LogOff401", new { id = random })%>',
    type: 'POST',
    username: '<%:random%>',
    password: '<%:random%>',
    success: function () { alert('logged off'); }
});

3)第一次应该总是返回 401(强制传递新的凭证),然后只接受虚拟凭证:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogOff401(string id)
{
    // if we've been passed HTTP authorisation
    string httpAuth = this.Request.Headers["Authorization"];
    if (!string.IsNullOrEmpty(httpAuth) &&
        httpAuth.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
    {
        // build the string we expect - don't allow regular users to pass
        byte[] enc = Encoding.UTF8.GetBytes(id + ':' + id);
        string expected = "basic " + Convert.ToBase64String(enc);

        if (string.Equals(httpAuth, expected, StringComparison.OrdinalIgnoreCase))
        {
            return Content("You are logged out.");
        }
    }

    // return a request for an HTTP basic auth token, this will cause XmlHttp to pass the new header
    this.Response.StatusCode = 401; 
    this.Response.StatusDescription = "Unauthorized";
    this.Response.AppendHeader("WWW-Authenticate", "basic realm=\"My Realm\""); 

    return Content("Force AJAX component to sent header");
}

4) 现在随机字符串凭据已被浏览器接受并缓存。当他们访问另一个页面时,它会尝试使用它们,失败,然后提示正确的页面。

请注意,我的代码示例使用的是 jQuery 和 ASP.Net MVC,但任何技术堆栈都应该可以实现同样的事情。

在 IE6 及更高版本中还有另一种方法可以做到这一点:

document.execCommand("ClearAuthenticationCache");

但是,这会清除所有身份验证 - 他们从我的网站注销,他们也从他们的电子邮件中注销。所以就这样了。

有没有更好的方法来做到这一点?

我已经看到了其他 问题,但它们已经 2 岁了 - 现在在 IE9、FX4、Chrome 等中有没有更好的方法?

如果没有更好的方法可以做到这一点,是否可以依靠这个结块?有什么办法让它更健壮吗?

4

1 回答 1

5

简短的回答是:
鉴于当前基本身份验证的实现,没有可靠的程序可以使用 HTTP 基本或摘要身份验证来实现“注销”。

此类身份验证通过让客户端向请求添加Authorization标头来工作。
如果对于某个资源,服务器对提供的凭据不满意(例如,如果没有),它将以“401 Unauthorized”状态代码响应并请求身份验证。为此,它将在响应中提供一个WWW-Authenticate标头。

客户端不需要等待服务器请求身份验证。它可以简单地基于一些本地假设(例如,上次成功尝试的缓存信息)提供授权标头。

虽然您概述的“清除”身份验证信息的方法很有可能与广泛的客户端(即广泛使用的浏览器)一起工作,但绝对不能保证另一个客户端可能“更聪明”并且只是区分正确的身份验证数据您的“注销”页面和目标站点的任何其他页面。

在使用基于客户端证书的身份验证时,您会发现类似的“问题”。只要没有客户的明确支持,您就可能会在失地的情况下战斗。

因此,如果“注销”是一个问题,请转到任何基于会话的身份验证。

如果您有权访问服务器端的身份验证实现,您可能能够实现一个功能,该功能将根据您的应用程序级代码的请求,忽略使用Authorization标头呈现的身份验证信息(如果仍然与当前“会话期间呈现的内容相同”) (或提供一些“超时”,之后将重新请求任何凭据),以便客户端将要求用户提供“新”凭据(执行新登录)。

于 2016-03-02T13:58:18.327 回答