Как выйти из системы с веб-сайта, используя аутентификацию BASIC?

StackOverflow https://stackoverflow.com/questions/233507

Вопрос

Можно ли выйти из системы пользователя с веб-сайта, если он использует базовую аутентификацию?

Завершения сеанса недостаточно, поскольку после аутентификации пользователя каждый запрос содержит информацию для входа, поэтому пользователь автоматически входит в систему при следующем доступе к сайту, используя те же учетные данные.

Пока единственное решение — закрыть браузер, но это неприемлемо с точки зрения удобства использования.

Это было полезно?

Решение

Обычная аутентификация не предназначена для управления выходом из системы. Вы можете сделать это, но не полностью автоматически.

Вам нужно сделать так, чтобы пользователь щелкнул ссылку выхода из системы и отправил & # 8216; 401 Unauthorized & # 8217; в ответ, используя ту же область и тот же уровень URL-папки, что и обычный 401, который вы отправляете, запрашивая логин.

Они должны быть направлены на ввод неправильных учетных данных, например. пустое имя пользователя и пароль, и в ответ вы отправляете обратно & # 8220; Вы успешно вышли из системы & # 8221; стр. Неверные / пустые учетные данные затем перезапишут предыдущие правильные учетные данные.

Короче говоря, сценарий выхода из системы инвертирует логику сценария входа в систему, возвращая страницу успеха только в том случае, если пользователь не передает правильные учетные данные.

Вопрос в том, не любопытно ли & # 8220; не вводить свой пароль & # 8221; окно пароля будет соответствовать принятию пользователя. Менеджеры паролей, которые пытаются автоматически заполнить пароль, также могут воспрепятствовать этому.

Отредактируйте, чтобы добавить в ответ на комментарий: повторный вход - это немного другая проблема (если, конечно, вам не требуется двухэтапный выход из системы / вход в систему). Вы должны отклонить (401) первую попытку доступа к ссылке повторной регистрации, чем принять вторую (которая предположительно имеет другое имя пользователя / пароль). Есть несколько способов сделать это. Можно было бы включить текущее имя пользователя в ссылку выхода из системы (например, / relogin? Username) и отклонить, когда учетные данные соответствуют имени пользователя.

Другие советы

Дополнение к ответу от bobince ...

С Ajax вы можете привязать ссылку / кнопку «Выход» к функции Javascript. Пусть эта функция отправит XMLHttpRequest с неверным именем пользователя и паролем. Это должно вернуть 401. Затем верните document.location на страницу перед входом в систему. Таким образом, пользователь никогда не увидит дополнительное диалоговое окно входа в систему и не должен будет вводить неверные учетные данные.

Пусть пользователь нажмет на ссылку на https: // log: out@example.com/ . Это заменит существующие учетные данные недействительными; выходя из них.

Вы можете сделать это полностью в JavaScript:

IE имеет (долгое время) стандартный API для очистки кэша базовой аутентификации:

document.execCommand("ClearAuthenticationCache")

Должен возвращать true, когда это работает. Возвращает false, undefined или разрывается в других браузерах.

Новые браузеры (по состоянию на декабрь 2012 года: 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@')

" асинхронный " один из способов сделать это - выполнить AJAX-вызов, используя имя пользователя logout . Пример:

(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 = " Вы должны выйти из системы сейчас. " ;; 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 || местоположение) .href,! 0, «выход из системы», (новая дата) .getTime (). toString ()), a.send («quot;»), a = 1): a = void 0); a || ( b = " Ваш браузер слишком старый или слишком странный для поддержки функций выхода из системы. Закройте все окна и перезапустите браузер. "); alert (b)}) (/ * передайте safeLocation здесь, если вам нужно * /);

Подтверждено, что следующая функция работает в Firefox 40, Chrome 44, Opera 31 и IE 11.
Баузер используется для обнаружения браузера, также используется 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);
}

Это невозможно напрямую с Basic-Authentication.

В спецификации HTTP нет механизма, позволяющего серверу указывать браузеру прекратить отправку учетных данных, которые уже были представлены пользователем.

Есть "взломы" (см. другие ответы), как правило, с использованием XMLHttpRequest для отправки HTTP-запроса с неверными учетными данными, чтобы перезаписать первоначально предоставленные.

Вот очень простой пример Javascript с использованием jQuery:

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;
}

Все, что вам нужно, это перенаправить пользователя на какой-либо URL-адрес выхода и вернуть ошибку 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) Есть много способов сделать это, я создал два бэкэнда входа в систему, один из которых принимает пользователя, а другой нет. Моя обычная страница входа использует ту, которая не принимает, моя страница выхода использует ту, которая ее принимает.

  • используйте идентификатор сеанса (cookie)
  • сделать недействительным идентификатор сеанса на сервере
  • Не принимать пользователей с недействительными идентификаторами сеансов

Я обновил решение mthoring для современных версий Chrome:

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