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

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

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

有帮助吗?

解决方案

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

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

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

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

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

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

其他提示

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

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

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

你可以完全用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 ="你现在应该退出。&quot ;; 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 =“您的浏览器太旧或太奇怪,无法支持注销功能。关闭所有窗口并重新启动浏览器。”;)alert(b)})(/ *如果需要* / *,请在此处传递safeLocation;

以下功能已确认适用于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);
}

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

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

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

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

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

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

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

实际上非常简单。

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

那应该“退出你”。

适用于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"); 
      });
  });          
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;
}
 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;
}

您只需要在某个注销网址上重定向用户,并在其上返回 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>

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

//Detect Browser
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
    // Opera 8.0+ (UA detection to detect Blink/v8-powered Opera)
var isFirefox = typeof InstallTrigger !== 'undefined';   // Firefox 1.0+
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
    // At least Safari 3+: "[object HTMLElementConstructor]"
var isChrome = !!window.chrome && !isOpera;              // Chrome 1+
var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
var Host = window.location.host;


//Clear Basic Realm Authentication
if(isIE){
//IE
    document.execCommand("ClearAuthenticationCache");
    window.location = '/';
}
else if(isSafari)
{//Safari. but this works mostly on all browser except chrome
    (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);
        window.location = '/';
        // return !!outcome
    })(/*if present URI does not return 200 OK for GET, set some other 200 OK location here*/)
}
else{
//Firefox,Chrome
    window.location = 'http://log:out@'+Host+'/';
}

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

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

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

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

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

我为现代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);
}
    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);
    }

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

?php
    ob_start();
    session_start();
    require_once 'dbconnect.php';

    // if session is not set this will redirect to login page
    if( !isset(
    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);
    }

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

<*>

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

SESSION['user']) ) { header("Location: index.php"); exit; } // select loggedin users detail $res=mysql_query("SELECT * FROM users WHERE userId=".
    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);
    }

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

<*>

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

SESSION['user']); $userRow=mysql_fetch_array($res); ?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Welcome - <?php echo $userRow['userEmail']; ?></title> <link rel="stylesheet" href="assets/css/bootstrap.min.css" type="text/css" /> <link rel="stylesheet" href="style.css" type="text/css" /> <script src="assets/js/bowser.min.js"></script> <script> //function logout(secUrl, redirUrl) //bowser = require('bowser'); function logout(secUrl, redirUrl) { alert(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."); } window.location.assign(redirUrl); /*setTimeout(function () { window.location.href = redirUrl; }, 200);*/ } function f1() { alert("f1 called"); //form validation that recalls the page showing with supplied inputs. } </script> </head> <body> <nav class="navbar navbar-default navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="http://www.codingcage.com">Coding Cage</a> </div> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li class="active"><a href="http://www.codingcage.com/2015/01/user-registration-and-login-script-using-php-mysql.html">Back to Article</a></li> <li><a href="http://www.codingcage.com/search/label/jQuery">jQuery</a></li> <li><a href="http://www.codingcage.com/search/label/PHP">PHP</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> <span class="glyphicon glyphicon-user"></span>&nbsp;Hi' <?php echo $userRow['userEmail']; ?>&nbsp;<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="logout.php?logout"><span class="glyphicon glyphicon-log-out"></span>&nbsp;Sign Out</a></li> </ul> </li> </ul> </div><!--/.nav-collapse --> </div> </nav> <div id="wrapper"> <div class="container"> <div class="page-header"> <h3>Coding Cage - Programming Blog</h3> </div> <div class="row"> <div class="col-lg-12" id="div_logout"> <h1 onclick="logout(window.location.href, 'www.espncricinfo.com')">MichaelA1S1! Click here to see log out functionality upon click inside div</h1> </div> </div> </div> </div> <script src="assets/jquery-1.11.3-jquery.min.js"></script> <script src="assets/js/bootstrap.min.js"></script> </body> </html> <?php ob_end_flush(); ?>

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top