Pergunta

É possível registrar o usuário de um site se ele estiver usando autenticação básica?

A sessão de matar não é suficiente, uma vez que, uma vez que o usuário é autenticado, cada solicitação contém informações de login; portanto, o usuário está conectado automaticamente na próxima vez que acessar o site usando as mesmas credenciais.

A única solução até agora é fechar o navegador, mas isso não é aceitável do ponto de vista da usabilidade.

Foi útil?

Solução

A autenticação básica não foi projetada para gerenciar o registro. Você pode fazer isso, mas não completamente automaticamente.

O que você precisa fazer é fazer com que o usuário clique em um link de logout e enviar um '401 não autorizado' em resposta, usando o mesmo reino e no mesmo nível de pasta URL do 401 normal que você envia solicitando um login.

Eles devem ser direcionados para inserir credenciais erradas a seguir, por exemplo. Uma palavra em branco de nome de usuário e passagem e, em resposta, você envia de volta uma página "Você registrou com sucesso". As credenciais erradas/em branco substituirão as credenciais corretas anteriores.

Em resumo, o script de logout inverte a lógica do script de login, retornando apenas a página de sucesso se o usuário não é passando as credenciais certas.

A questão é se a caixa de senha um tanto curiosa “não digite sua senha” atenderá à aceitação do usuário. Os gerentes de senha que tentam preencher automaticamente a senha também podem atrapalhar aqui.

Editar para adicionar em resposta ao comentário: O re-log-in é um problema ligeiramente diferente (a menos que você precise de um logout/login em duas etapas, obviamente). Você deve rejeitar (401) a primeira tentativa de acessar o link Relogin, do que aceitar o segundo (que presumivelmente possui um nome de usuário/senha diferente). Existem algumas maneiras de fazer isso. Seria incluir o nome de usuário atual no link de logout (por exemplo, /Relogin? Nome de usuário) e rejeitar quando as credenciais correspondem ao nome de usuário.

Outras dicas

Uma adição à resposta de Bobince ...

Com o Ajax, você pode ter seu link/botão 'logout' conectado a uma função JavaScript. Peça a essa função que envie o XmlHttPrequest com um nome de usuário e senha ruim. Isso deve recuperar um 401. Em seguida, defina o documento.Location de volta à página Pré-Login. Dessa forma, o usuário nunca verá a caixa de diálogo de login extra durante o logout, nem deve se lembrar de colocar credenciais ruins.

Peça ao usuário que clique em um link para https: // log: out@example.com/. Isso substituirá as credenciais existentes com as inválidas; registrando -os fora.

Você pode fazer isso inteiramente em JavaScript:

O IE possui (por um longo tempo) API padrão para limpar o cache básico de autenticação:

document.execCommand("ClearAuthenticationCache")

Deve retornar verdadeiro quando funciona. Retorna falsa, indefinida ou explode em outros navegadores.

Novos navegadores (em dezembro de 2012: Chrome, Firefox, Safari) têm comportamento "mágico". Se eles virem um bem sucedido solicitação de autenticação básica com qualquer outro nome de usuário falso (digamos logout) Eles limpam o cache de credenciais e possivelmente o definem para esse novo nome de usuário falso, que você precisa garantir que não seja um nome de usuário válido para visualizar o conteúdo.

Exemplo básico disso é:

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

Uma maneira "assíncrona" de fazer o exposto é fazer uma chamada de Ajax utilizando o logout nome de usuário. Exemplo:

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

Você também pode fazer um Bookmarklet:

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

A seguinte função é confirmada trabalhando para o Firefox 40, Chrome 44, Opera 31 e IE 11.
Bowser é usado para detecção de navegador, o jQuery também é usado.

- Securl é o URL para uma área protegida por senha a partir da qual fazer logon.
- Redirurl é o URL para uma área não protegida por senha (página de sucesso de logout).
- Você pode aumentar o timer de redirecionamento (atualmente 200ms).

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

Isso não é diretamente possível com a autenticação básica.

Não há mecanismo na especificação HTTP para o servidor dizer ao navegador para parar de enviar as credenciais que o usuário já apresentou.

Existem "hacks" (veja outras respostas) envolvendo o uso do XMLHTTPRequest para enviar uma solicitação HTTP com credenciais incorretas para substituir as originalmente fornecidas.

Aqui está um exemplo JavaScript muito simples usando o jQuery:

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

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

Este usuário de log fora sem mostrar a ele a caixa de login do navegador novamente e depois redirecioná-lo para um desconectado página

É realmente muito simples.

Basta visitar o seguinte no seu navegador e usar credenciais erradas:http: // nome de usuário: password@yourdomain.com

Isso deve "registrar você".

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

Tudo que você precisa é redirecionar o usuário em algum URL de logout e retornar 401 Unauthorized erro nele. Na página de erro (que deve estar acessível sem autenticação básica), você precisa fornecer um link completo para sua página inicial (incluindo esquema e nome de host). O usuário clicará neste link e o navegador solicitará credenciais novamente.

Exemplo 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 erro /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 deve estar funcionando para todos os navegadores da versão mais recente:

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

Adicione isso ao seu aplicativo:

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

Com base no que li acima, recebi uma solução simples que funciona em qualquer navegador:

1) Na sua página de logout, você chama um Ajax no seu login back -end. Seu login back end deve aceitar o usuário de logout. Depois que o back -end aceitar, o navegador limpa o usuário atual e assume o usuário "logout".

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

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

2) Agora, quando o usuário voltou ao arquivo de índice normal, ele tentará inserir automático no sistema com o usuário "Logout", nesta segunda vez, você deve bloqueá -lo pela resposta com 401 para invocar a caixa de diálogo Login/senha.

3) Existem muitas maneiras de fazer isso, criei dois backins de login, um que aceita o usuário de logout e um que não. Minha página de login normal use a que não aceita, minha página de logout usa a que a aceita.

  • Use um ID da sessão (cookie)
  • invalidar o ID da sessão no servidor
  • Não aceite usuários com IDs de sessão inválidos

Atualizei a solução de Mthoring para versões do Chrome modernas:

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

Eu tentei usar o acima da seguinte maneira.

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

    // if session is not set this will redirect to login page
    if( !isset($_SESSION['user']) ) {
        header("Location: index.php");
        exit;
    }
    // select loggedin users detail
    $res=mysql_query("SELECT * FROM users WHERE userId=".$_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(); ?>

Mas apenas o redireciona para um novo local. Sem logout.

modelo chrome://restart Na barra de endereços e Chrome, com todos os seus aplicativos em segundo plano, reiniciará e o cache de senha do AUTH será limpo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top