如何使用BASIC身份验证从Web站点注销用户?

时间:2008-10-24 13:21:35

标签: http authentication basic-authentication http-basic-authentication

如果用户使用基本身份验证,是否可以从网站注销用户?

杀戮会话是不够的,因为一旦用户通过身份验证,每个请求都包含登录信息,因此用户下次使用相同的凭据访问该站点时会自动登录。

到目前为止,唯一的解决方案是关闭浏览器,但从可用性的角度来看,这是不可接受的。

23 个答案:

答案 0 :(得分:189)

bobince对答案的补充......

使用Ajax,您可以将“Logout”链接/按钮连接到Javascript函数。让此函数使用错误的用户名和密码发送XMLHttpRequest。这应该返回401.然后将document.location设置回登录前页面。这样,用户在注销时将永远不会看到额外的登录对话框,也不必记得输入错误的凭据。

答案 1 :(得分:171)

让用户点击指向https://log:out@example.com/的链接。这将用无效的凭证覆盖现有的凭证;将它们记录下来。

答案 2 :(得分:155)

基本身份验证不是为了管理注销而设计的。你可以这样做,但不是完全自动的。

您需要做的是让用户点击退出链接,并使用相同的域发送“401 Unauthorized”,并使用与您发送的请求登录的普通401相同的URL文件夹级别。

接下来必须指示他们输入错误的凭证,例如。一个空白的用户名和密码,作为回应,您发回“您已成功注销”页面。然后,错误/空白凭证将覆盖先前正确的凭证。

简而言之,logout脚本会反转登录脚本的逻辑,只有在用户传递正确的凭据时才返回成功页面。

问题是,有点好奇的“不输入密码”密码框是否会满足用户的接受程度。尝试自动填写密码的密码管理员也会妨碍这里。

编辑以添加以回应评论:重新登录是一个稍微不同的问题(除非您需要两步注销/登录显然)。您必须拒绝(401)第一次尝试访问relogin链接,而不是接受第二次尝试(可能有不同的用户名/密码)。有几种方法可以做到这一点。一种方法是在注销链接中包含当前用户名(例如/ relogin?username),并在凭据与用户名匹配时拒绝。

答案 3 :(得分:61)

你可以完全用JavaScript完成:

IE(很长一段时间)标准API用于清除基本身份验证缓存:

document.execCommand("ClearAuthenticationCache")

当它工作时应该返回true。返回false,undefined或在其他浏览器上爆炸。

新浏览器(截至2012年12月:Chrome,FireFox,Safari)具有“魔力”行为。如果他们看到一个成功的基本身份验证请求,其中包含任何虚假的其他用户名(假设为logout),他们会清除凭据缓存,并可能为新的虚假用户名设置它,您需要进行此操作确定不是用于查看内容的有效用户名。

基本的例子是:

var p = window.location.protocol + '//'
// current location must return 200 OK for this GET
window.location = window.location.href.replace(p, p + 'logout:password@')

执行上述操作的“异步”方法是使用logout用户名进行AJAX调用。例如:

(function(safeLocation){
    var outcome, u, m = "You should be logged out now.";
    // IE has a simple solution for it - API:
    try { outcome = document.execCommand("ClearAuthenticationCache") }catch(e){}
    // Other browsers need a larger solution - AJAX call with special user name - 'logout'.
    if (!outcome) {
        // Let's create an xmlhttp object
        outcome = (function(x){
            if (x) {
                // the reason we use "random" value for password is 
                // that browsers cache requests. changing
                // password effectively behaves like cache-busing.
                x.open("HEAD", safeLocation || location.href, true, "logout", (new Date()).getTime().toString())
                x.send("")
                // x.abort()
                return 1 // this is **speculative** "We are done." 
            } else {
                return
            }
        })(window.XMLHttpRequest ? new window.XMLHttpRequest() : ( window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : u ))
    }
    if (!outcome) {
        m = "Your browser is too old or too weird to support log out functionality. Close all windows and restart the browser."
    }
    alert(m)
    // return !!outcome
})(/*if present URI does not return 200 OK for GET, set some other 200 OK location here*/)

你也可以把它作为书签:

javascript:(function(c){var a,b="You should be logged out now.";try{a=document.execCommand("ClearAuthenticationCache")}catch(d){}a||((a=window.XMLHttpRequest?new window.XMLHttpRequest:window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):void 0)?(a.open("HEAD",c||location.href,!0,"logout",(new Date).getTime().toString()),a.send(""),a=1):a=void 0);a||(b="Your browser is too old or too weird to support log out functionality. Close all windows and restart the browser.");alert(b)})(/*pass safeLocation here if you need*/);

答案 4 :(得分:16)

以下功能已确认适用于Firefox 40,Chrome 44,Opera 31和IE 11 Bowser用于浏览器检测,也使用jQuery。

- secUrl是密码保护区域的URL,可以从中注销 - redirUrl是非密码保护区域的URL(注销成功页面)。
- 您可能希望增加重定向计时器(当前为200毫秒)。



function logout(secUrl, redirUrl) {
    if (bowser.msie) {
        document.execCommand('ClearAuthenticationCache', 'false');
    } else if (bowser.gecko) {
        $.ajax({
            async: false,
            url: secUrl,
            type: 'GET',
            username: 'logout'
        });
    } else if (bowser.webkit) {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", secUrl, true);
        xmlhttp.setRequestHeader("Authorization", "Basic logout");
        xmlhttp.send();
    } else {
        alert("Logging out automatically is unsupported for " + bowser.name
            + "\nYou must close the browser to log out.");
    }
    setTimeout(function () {
        window.location.href = redirUrl;
    }, 200);
}




答案 5 :(得分:10)

使用基本身份验证无法直接进行此操作。

HTTP规范中没有机制告诉浏览器停止发送用户已经提供的凭据。

有“hacks”(参见其他答案)通常涉及使用XMLHttpRequest发送带有错误凭据的HTTP请求来覆盖最初提供的HTTP请求。

答案 6 :(得分:9)

这是一个使用jQuery的简单Javascript示例:

function logout(to_url) {
    var out = window.location.href.replace(/:\/\//, '://log:out@');

    jQuery.get(out).error(function() {
        window.location = to_url;
    });
}

此日志用户没有再次向他显示浏览器登录框,然后将其重定向到已注销的页面

答案 7 :(得分:6)

实际上非常简单。

只需在浏览器中访问以下内容并使用错误的凭据: http://username:password@yourdomain.com

那应该“退出你”。

答案 8 :(得分:5)

适用于IE / Netscape / Chrome:

      function ClearAuthentication(LogOffPage) 
  {
     var IsInternetExplorer = false;    

     try
     {
         var agt=navigator.userAgent.toLowerCase();
         if (agt.indexOf("msie") != -1) { IsInternetExplorer = true; }
     }
     catch(e)
     {
         IsInternetExplorer = false;    
     };

     if (IsInternetExplorer) 
     {
        // Logoff Internet Explorer
        document.execCommand("ClearAuthenticationCache");
        window.location = LogOffPage;
     }
     else 
     {
        // Logoff every other browsers
    $.ajax({
         username: 'unknown',
         password: 'WrongPassword',
             url: './cgi-bin/PrimoCgi',
         type: 'GET',
         beforeSend: function(xhr)
                 {
            xhr.setRequestHeader("Authorization", "Basic AAAAAAAAAAAAAAAAAAA=");
         },

                 error: function(err)
                 {
                    window.location = LogOffPage;
             }
    });
     }
  }


  $(document).ready(function () 
  {
      $('#Btn1').click(function () 
      {
         // Call Clear Authentication 
         ClearAuthentication("force_logout.html"); 
      });
  });          

答案 9 :(得分:2)

function logout() {
  var userAgent = navigator.userAgent.toLowerCase();

  if (userAgent.indexOf("msie") != -1) {
    document.execCommand("ClearAuthenticationCache", false);
  }

  xhr_objectCarte = null;

  if(window.XMLHttpRequest)
    xhr_object = new XMLHttpRequest();
  else if(window.ActiveXObject)
    xhr_object = new ActiveXObject("Microsoft.XMLHTTP");
  else
    alert ("Your browser doesn't support XMLHTTPREQUEST");

  xhr_object.open ('GET', 'http://yourserver.com/rep/index.php', false, 'username', 'password');
  xhr_object.send ("");
  xhr_object = null;

  document.location = 'http://yourserver.com'; 
  return false;
}

答案 10 :(得分:2)

 function logout(url){
    var str = url.replace("http://", "http://" + new Date().getTime() + "@");
    var xmlhttp;
    if (window.XMLHttpRequest) xmlhttp=new XMLHttpRequest();
    else xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    xmlhttp.onreadystatechange=function()
    {
        if (xmlhttp.readyState==4) location.reload();
    }
    xmlhttp.open("GET",str,true);
    xmlhttp.setRequestHeader("Authorization","Basic xxxxxxxxxx")
    xmlhttp.send();
    return false;
}

答案 11 :(得分:2)

发送https://invalid_login@hostname可以在Mac上的Safari以外的所有地方正常工作(很好,未选中Edge,但也可以在那里工作)。

当用户在HTTP基本身份验证弹出窗口中选择“记住密码”时,

注销在Safari中不起作用。在这种情况下,密码存储在“钥匙串访问”中(“查找器”>“应用程序”>“实用程序”>“钥匙串访问”(或CMD + SPACE并键入“钥匙串访问”))。发送https://invalid_login@hostname不会影响“钥匙串访问”,因此使用此复选框无法在Mac上的Safari上注销。至少它对我有用。

MacOS Mojave(10.14.6),Safari 12.1.2。

以下代码对我来说在Firefox(73),Chrome(80)和Safari(12)中正常运行。当用户导航到注销页面时,将执行代码并删除凭据。

    //It should return 401, necessary for Safari only
    const logoutUrl = 'https://example.com/logout'; 
    const xmlHttp = new XMLHttpRequest();
    xmlHttp.open('POST', logoutUrl, true, 'logout');
    xmlHttp.send();

由于某些原因,即使选择了“记住密码”,Safari也不会在HTTP Basic Authentication弹出窗口中保存凭据。其他浏览器可以正确执行此操作。

答案 12 :(得分:1)

将此添加到您的应用程序中:

@app.route('/logout')
def logout():
    return ('Logout', 401, {'WWW-Authenticate': 'Basic realm="Login required"'})

答案 13 :(得分:1)

您只需要在某个注销网址上重定向用户,并在其上返回401 Unauthorized错误。在错误页面上(必须可以在没有基本身份验证的情况下访问),您需要提供主页的完整链接(包括方案和主机名)。用户将单击此链接,浏览器将再次请求凭据。

Nginx的例子:

location /logout {
    return 401;
}

error_page 401 /errors/401.html;

location /errors {
    auth_basic off;
    ssi        on;
    ssi_types  text/html;
    alias /home/user/errors;
}

错误页面/home/user/errors/401.html

<!DOCTYPE html>
<p>You're not authorised. <a href="<!--# echo var="scheme" -->://<!--# echo var="host" -->/">Login</a>.</p>

答案 14 :(得分:1)

根据我上面的内容,我得到了一个适用于任何浏览器的简单解决方案:

1)在您的注销页面上,您将ajax调用到您的登录后端。您的登录后端必须接受注销用户。一旦后端接受,浏览器将清除当前用户并假定“注销”用户。

$.ajax({
    async: false,
    url: 'http://your_login_backend',
    type: 'GET',
    username: 'logout'
});      

setTimeout(function () {
    window.location.href = 'http://normal_index';
}, 200);

2)现在当用户回到正常的索引文件时,它将尝试使用用户“logout”自动进入系统,在第二次你必须通过回复401来调用登录/密码对话框。

3)有很多方法可以做到这一点,我创建了两个登录后端,一个接受注销用户,另一个不接受注销。我的普通登录页面使用的是不接受的页面,我的登出页面使用接受它的页面。

答案 15 :(得分:0)

正如其他人所说,我们需要获取相同的 URL 并发送错误(例如,401:StatusUnauthorized 之类的),就是这样。

我使用 Get 方法让它知道我需要注销,

这是使用 golang 编写的完整示例。

Scrollable

当您已经注销时,您需要刷新 (F5) 页面。否则,您可能会看到旧内容。

答案 16 :(得分:0)

  • 使用会话ID(cookie)
  • 使服务器上的会话ID无效
  • 不接受会话ID无效的用户

答案 17 :(得分:0)

我刚刚在Chrome(79),Firefox(71)和Edge(44)中测试了以下内容,并且工作正常。如上文所述,它将应用脚本解决方案。

只需添加“注销”链接,然后单击即可返回以下html

    <div>You have been logged out. Redirecting to home...</div>    

<script>
    var XHR = new XMLHttpRequest();
    XHR.open("GET", "/Home/MyProtectedPage", true, "no user", "no password");
    XHR.send();

    setTimeout(function () {
        window.location.href = "/";
    }, 3000);
</script>

答案 18 :(得分:0)

仅作记录,就有一个名为Clear-Site-Data的新HTTP响应标头。如果您的服务器回复中包含Clear-Site-Data: "cookies"标头,则应删除身份验证凭据(不仅限于cookie)。我在Chrome 77上进行了测试,但此警告在控制台上显示:

Clear-Site-Data header on 'https://localhost:9443/clear': Cleared data types:
"cookies". Clearing channel IDs and HTTP authentication cache is currently not
supported, as it breaks active network connections.

并且不会删除身份验证凭据,因此(暂时)无法实现基本身份验证注销,但将来可能会实现。未在其他浏览器上进行测试。

参考文献:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data

https://www.w3.org/TR/clear-site-data/

https://github.com/w3c/webappsec-clear-site-data

https://caniuse.com/#feat=mdn-http_headers_clear-site-data_cookies

答案 19 :(得分:0)

在地址栏和镶边中键入chrome://restart,并且其所有应用程序都在后台运行,它们将重新启动,并且将清除Auth密码缓存。

答案 20 :(得分:0)

我为现代Chrome版本更新了mthoring的解决方案:

function logout(secUrl, redirUrl) {
    if (bowser.msie) {
        document.execCommand('ClearAuthenticationCache', 'false');
    } else if (bowser.gecko) {
        $.ajax({
            async: false,
            url: secUrl,
            type: 'GET',
            username: 'logout'
        });
    } else if (bowser.webkit || bowser.chrome) {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open(\"GET\", secUrl, true);
        xmlhttp.setRequestHeader(\"Authorization\", \"Basic logout\");\
        xmlhttp.send();
    } else {
// http://stackoverflow.com/questions/5957822/how-to-clear-basic-authentication-details-in-chrome
        redirUrl = url.replace('http://', 'http://' + new Date().getTime() + '@');
    }
    setTimeout(function () {
        window.location.href = redirUrl;
    }, 200);
}

答案 21 :(得分:0)

    function logout(secUrl, redirUrl) {
        if (bowser.msie) {
            document.execCommand('ClearAuthenticationCache', 'false');
        } else if (bowser.gecko) {
            $.ajax({
                async: false,
                url: secUrl,
                type: 'GET',
                username: 'logout'
            });
        } else if (bowser.webkit) {
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open("GET", secUrl, true);
            xmlhttp.setRequestHeader("Authorization", "Basic logout");
            xmlhttp.send();
        } else {
            alert("Logging out automatically is unsupported for " + bowser.name
                + "\nYou must close the browser to log out.");
        }
        setTimeout(function () {
            window.location.href = redirUrl;
        }, 200);
    }

我尝试以下列方式使用上述内容。

    function logout(secUrl, redirUrl) {
        if (bowser.msie) {
            document.execCommand('ClearAuthenticationCache', 'false');
        } else if (bowser.gecko) {
            $.ajax({
                async: false,
                url: secUrl,
                type: 'GET',
                username: 'logout'
            });
        } else if (bowser.webkit) {
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open("GET", secUrl, true);
            xmlhttp.setRequestHeader("Authorization", "Basic logout");
            xmlhttp.send();
        } else {
            alert("Logging out automatically is unsupported for " + bowser.name
                + "\nYou must close the browser to log out.");
        }
        setTimeout(function () {
            window.location.href = redirUrl;
        }, 200);
    }

但它只会将您重定向到新位置。没有注销。

答案 22 :(得分:0)

此JavaScript必须适用于所有最新版本的浏览器:

var economy= { 
init: function () {
$('input[type="text"][data-require-numeric]').on("change keyup paste", function () {
        check isnumeric; if yes then border red
    });
}};
$(economy.init);