Pregunta

¿Es posible desconectar al usuario de un sitio web si está usando autenticación básica?

La sesión de asesinato no es suficiente, ya que, una vez que el usuario se autentica, cada solicitud contiene información de inicio de sesión, por lo que el usuario inicia sesión automáticamente la próxima vez que acceda al sitio con las mismas credenciales.

La única solución hasta ahora es cerrar el navegador, pero eso no es aceptable desde el punto de vista de la usabilidad.

¿Fue útil?

Solución

La autenticación básica no fue diseñada para administrar el cierre de sesión. Puedes hacerlo, pero no de forma completamente automática.

Lo que tiene que hacer es hacer que el usuario haga clic en un enlace de cierre de sesión y envíe un '401 no autorizado' en respuesta, utilizando el mismo dominio y en el mismo nivel de carpeta de URL que el 401 que envía normalmente solicitando un inicio de sesión.

A continuación, deben dirigirse para ingresar las credenciales incorrectas, p. ej. un nombre de usuario y contraseña en blanco, y en respuesta envía una página de "Ha cerrado la sesión correctamente". Las credenciales incorrectas / en blanco sobrescribirán las credenciales correctas anteriores.

En resumen, el script de cierre de sesión invierte la lógica del script de inicio de sesión, solo devuelve la página de éxito si el usuario no pasa las credenciales correctas.

La pregunta es si el curioso cuadro de contraseña "no ingrese su contraseña" cumplirá con la aceptación del usuario. Los administradores de contraseñas que intentan completar automáticamente la contraseña también pueden interferir aquí.

Editar para agregar en respuesta al comentario: volver a iniciar sesión es un problema ligeramente diferente (a menos que necesite un cierre de sesión / inicio de sesión de dos pasos, obviamente). Debe rechazar (401) el primer intento de acceso al enlace de reinicio de sesión, y aceptar el segundo (que presumiblemente tiene un nombre de usuario / contraseña diferente). Hay algunas maneras en que puedes hacer esto. Uno sería incluir el nombre de usuario actual en el enlace de cierre de sesión (por ejemplo, / relogin? Nombre de usuario) y rechazar cuando las credenciales coincidan con el nombre de usuario.

Otros consejos

Una adición a la respuesta de bobince ...

Con Ajax puede tener su enlace / botón 'Cerrar sesión' conectado a una función Javascript. Haga que esta función envíe el XMLHttpRequest con un nombre de usuario y contraseña incorrectos. Esto debería recuperar un 401. Luego, establezca document.location en la página de preinicio de sesión. De esta forma, el usuario nunca verá el diálogo de inicio de sesión adicional durante el cierre de sesión, ni tendrá que acordarse de poner credenciales incorrectas.

Haga que el usuario haga clic en un enlace a https: // log: out@example.com/ . Eso sobrescribirá las credenciales existentes con las inválidas; desconectándolos.

Puedes hacerlo completamente en JavaScript:

IE tiene (durante mucho tiempo) API estándar para borrar la caché de autenticación básica:

document.execCommand("ClearAuthenticationCache")

Debería devolver verdadero cuando funciona. Devuelve falso, indefinido o explota en otros navegadores.

Los nuevos navegadores (a partir de diciembre de 2012: Chrome, Firefox, Safari) tienen "magia" comportamiento. Si ven una solicitud de autenticación básica exitosa con cualquier otro nombre de usuario falso (digamos logout ), borran el caché de credenciales y posiblemente lo configuran para ese nuevo nombre de usuario falso, que usted puede es necesario asegurarse de que no sea un nombre de usuario válido para ver contenido.

Ejemplo básico de eso es:

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

Un " asíncrono " La forma de hacer lo anterior es hacer una llamada AJAX utilizando el nombre de usuario logout . Ejemplo:

(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*/)

También puedes convertirlo en un bookmarklet:

javascript: (función (c) {var a, b = " Debería estar desconectado ahora; intente {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 || ubicación .href,! 0, " logout ", (nueva Fecha) .getTime (). toString ()), a.send (" "), a = 1): a = void 0); a || ( b = " Su navegador es demasiado viejo o demasiado extraño para admitir la funcionalidad de cierre de sesión. Cierre todas las ventanas y reinicie el navegador. "); alert (b)}) (/ * pase safeLocation aquí si necesita * /);

Se confirma que la siguiente función funciona para Firefox 40, Chrome 44, Opera 31 e IE 11.
Bowser se usa para la detección del navegador, también se usa jQuery.

- secUrl es la url a un área protegida por contraseña desde la que cerrar sesión.
- redirUrl es la url a un área no protegida por contraseña (página de cierre de sesión exitosa).
- es posible que desee aumentar el temporizador de redireccionamiento (actualmente 200 ms).

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

Esto no es directamente posible con la autenticación básica.

En la especificación HTTP no hay ningún mecanismo para que el servidor le indique al navegador que deje de enviar las credenciales que el usuario ya presentó.

Hay "hacks" (ver otras respuestas) que generalmente involucran el uso de XMLHttpRequest para enviar una solicitud HTTP con credenciales incorrectas para sobrescribir las que se proporcionaron originalmente.

Aquí hay un ejemplo Javascript muy simple usando jQuery:

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

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

Este usuario de cierre de sesión sin mostrarle nuevamente el cuadro de inicio de sesión del navegador, luego lo redirecciona a una página desconectada

En realidad es bastante simple.

Simplemente visite lo siguiente en su navegador y use las credenciales incorrectas: http: // username: password@yourdomain.com

Eso debería " cerrar sesión " ;.

Esto está funcionando para 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;
}

Todo lo que necesita es redirigir al usuario en alguna URL de cierre de sesión y devolver el error 401 No autorizado . En la página de error (que debe ser accesible sin autenticación básica) debe proporcionar un enlace completo a su página de inicio (incluido el esquema y el nombre de host). El usuario hará clic en este enlace y el navegador volverá a solicitar credenciales.

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

Página de error /home/user/errors/401.html :

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

Este JavaScript debe estar funcionando para todos los navegadores de versiones más recientes:

//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+'/';
}

agregue esto a su aplicación:

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

Según lo que leí anteriormente, obtuve una solución simple que funciona en cualquier navegador:

1) en tu página de cierre de sesión, llamas a ajax a tu inicio de sesión. Su back-end de inicio de sesión debe aceptar el usuario que cierra sesión Una vez que el back end acepta, el navegador borra al usuario actual y asume el " cerrar sesión " usuario.

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

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

2) Ahora cuando el usuario regresó al archivo de índice normal, intentará ingresar automáticamente en el sistema con el usuario " logout " ;, en esta segunda vez, debe bloquearlo respondiendo con 401 para invocar el inicio de sesión / diálogo de contraseña.

3) Hay muchas formas de hacerlo, creé dos back-end de inicio de sesión, uno que acepta al usuario que cierra sesión y otro que no. Mi página de inicio de sesión normal usa la que no acepta, mi página de cierre de sesión usa la que la acepta.

  • usar una ID de sesión (cookie)
  • invalidar la ID de sesión en el servidor
  • No acepte usuarios con ID de sesión no válidos

Actualicé la solución de mthoring para las versiones modernas de 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);
    }

Intenté usar lo anterior de la siguiente manera.

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

Intenté usar lo anterior de la siguiente manera.

<*>

Pero solo te redirige a una nueva ubicación. Sin cerrar sesión.

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

Intenté usar lo anterior de la siguiente manera.

<*>

Pero solo te redirige a una nueva ubicación. Sin cerrar sesión.

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(); ?>

Pero solo te redirige a una nueva ubicación. Sin cerrar sesión.

escriba chrome: // restart en la barra de direcciones y Chrome, con todas sus aplicaciones que se ejecutan en segundo plano, se reiniciará y se limpiará la caché de contraseña de autenticación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top