sistema - sesiones multiusuario php
Cierre de autenticación HTTP a través de PHP (17)
Cerrar sesión desde HTTP Basic Auth en dos pasos
Digamos que tengo un dominio HTTP Auth Authentic llamado "Password protected" y Bob ha iniciado sesión. Para cerrar la sesión, realizo 2 solicitudes AJAX:
- Acceda a la secuencia de comandos / logout_step1. Agrega un usuario temporal aleatorio a .htusers y responde con su nombre de usuario y contraseña.
- Script de acceso / logout_step2 autenticado con el inicio de sesión y la contraseña del usuario temporal . El script elimina el usuario temporal y agrega este encabezado en la respuesta:
WWW-Authenticate: Basic realm="Password protected"
En este punto, el navegador olvidó las credenciales de Bob.
¿Cuál es la forma correcta de cerrar la sesión de la carpeta protegida con autenticación HTTP?
Existen soluciones provisionales que pueden lograrlo, pero son potencialmente peligrosas porque pueden tener errores o no funcionar en ciertas situaciones / navegadores. Es por eso que estoy buscando una solución correcta y limpia.
AFAIK, no hay una forma clara de implementar una función de "cierre de sesión" cuando se utiliza la autenticación htaccess (es decir, basada en HTTP).
Esto se debe a que dicha autenticación utiliza el código de error HTTP ''401'' para indicar al navegador que se necesitan credenciales, en cuyo momento el navegador solicita al usuario los detalles. A partir de ese momento, hasta que se cierre el navegador, siempre enviará las credenciales sin más indicaciones.
Aquí hay muchas respuestas geniales y complejas. En mi caso particular, encontré una solución limpia y simple para el cierre de sesión. Todavía tengo que probar en Edge. En mi página en la que me he conectado, he colocado un enlace de cierre de sesión similar a este:
<a href="https://MyDomainHere.net/logout.html">logout</a>
Y en la cabecera de esa página logout.html (que también está protegida por .htaccess) tengo una actualización de página similar a esta:
<meta http-equiv="Refresh" content="0; url=https://logout:[email protected]/" />
Donde dejaría las palabras "cerrar sesión" para borrar el nombre de usuario y la contraseña almacenados en caché para el sitio.
Admitiré que si se necesita poder acceder a varias páginas desde el principio, cada uno de esos puntos de entrada necesitaría su propia página logout.html correspondiente. De lo contrario, podría centralizar el cierre de sesión introduciendo un paso de portero adicional en el proceso antes de la solicitud de inicio de sesión real, que requiere la entrada de una frase para llegar a un destino de inicio de sesión.
Esta podría no ser la solución que se buscó pero lo resolví así. Tengo 2 scripts para el proceso de cierre de sesión.
logout.php
<?php
header("Location: http://[email protected]/log.php");
?>
log.php
<?php
header("location: https://google.com");
?>
De esta manera no recibo una advertencia y mi sesión finaliza
La única forma efectiva que he encontrado para eliminar las PHP_AUTH_DIGEST
o PHP_AUTH_USER
AND PHP_AUTH_PW
es llamar al encabezado HTTP/1.1 401 Unauthorized
.
function clear_admin_access(){
header(''HTTP/1.1 401 Unauthorized'');
die(''Admin access turned off'');
}
La mejor solución que encontré hasta ahora es (es una especie de pseudocódigo, $isLoggedIn
es una pseudovariable para http auth):
En el momento de "cerrar la sesión" simplemente guarde información en la sesión diciendo que el usuario está realmente desconectado.
function logout()
{
//$isLoggedIn = false; //This does not work (point of this question)
$_SESSION[''logout''] = true;
}
En el lugar donde verifico la autenticación, amplío la condición:
function isLoggedIn()
{
return $isLoggedIn && !$_SESSION[''logout''];
}
La sesión está relacionada de alguna manera con el estado de la autenticación http, por lo que el usuario permanece desconectado mientras mantenga el navegador abierto y mientras la autenticación http persista en el navegador.
La respuesta simple es que no puede cerrar sesión de manera confiable en la autenticación http.
La respuesta larga:
Http-auth (como el resto de la especificación HTTP) está destinado a ser sin estado. De modo que estar "conectado" o "desconectado" no es realmente un concepto que tenga sentido. La mejor forma de verlo es preguntar, por cada solicitud HTTP (y recordar que la carga de una página suele ser solicitudes múltiples), "¿se le permite hacer lo que está solicitando?". El servidor ve cada solicitud como nueva y no relacionada con ninguna solicitud anterior.
Los navegadores han elegido recordar las credenciales que les indica en el primer 401 y volver a enviarlas sin el permiso explícito del usuario en las solicitudes posteriores. Este es un intento de darle al usuario el modelo de "inicio de sesión / cierre de sesión" que esperan, pero es simplemente un desafío. Es el navegador que simula esta persistencia de estado. El servidor web no lo sabe por completo.
Por lo tanto, "cerrar la sesión", en el contexto de http-auth, es simplemente una simulación proporcionada por el navegador y, por lo tanto, está fuera de la autoridad del servidor.
Sí, hay kludges. Pero rompen REST-ness (si eso es de valor para ti) y no son confiables.
Si absolutamente requiere un modelo de inicio de sesión / sesión cerrada para la autenticación de su sitio, la mejor opción es una cookie de seguimiento, con la persistencia del estado almacenado en el servidor de alguna manera (mysql, sqlite, flatfile, etc.). Esto requerirá que todas las solicitudes sean evaluadas, por ejemplo, con PHP.
Método que funciona bien en Safari. También funciona en Firefox y Opera, pero con una advertencia.
Location: http://[email protected]/
Esto le dice al navegador que abra la URL con un nuevo nombre de usuario, anulando el anterior.
Mi solución al problema es la siguiente. Puede encontrar la función http_digest_parse
, $realm
y $users
en el segundo ejemplo de esta página: http://php.net/manual/en/features.http-auth.php .
session_start();
function LogOut() {
session_destroy();
session_unset($_SESSION[''session_id'']);
session_unset($_SESSION[''logged'']);
header("Location: /", TRUE, 301);
}
function Login(){
global $realm;
if (empty($_SESSION[''session_id''])) {
session_regenerate_id();
$_SESSION[''session_id''] = session_id();
}
if (!IsAuthenticated()) {
header(''HTTP/1.1 401 Unauthorized'');
header(''WWW-Authenticate: Digest realm="''.$realm.
''",qop="auth",nonce="''.$_SESSION[''session_id''].''",opaque="''.md5($realm).''"'');
$_SESSION[''logged''] = False;
die(''Access denied.'');
}
$_SESSION[''logged''] = True;
}
function IsAuthenticated(){
global $realm;
global $users;
if (empty($_SERVER[''PHP_AUTH_DIGEST'']))
return False;
// check PHP_AUTH_DIGEST
if (!($data = http_digest_parse($_SERVER[''PHP_AUTH_DIGEST''])) ||
!isset($users[$data[''username'']]))
return False;// invalid username
$A1 = md5($data[''username''] . '':'' . $realm . '':'' . $users[$data[''username'']]);
$A2 = md5($_SERVER[''REQUEST_METHOD''].'':''.$data[''uri'']);
// Give session id instead of data[''nonce'']
$valid_response = md5($A1.'':''.$_SESSION[''session_id''].'':''.$data[''nc''].'':''.$data[''cnonce''].'':''.$data[''qop''].'':''.$A2);
if ($data[''response''] != $valid_response)
return False;
return True;
}
Mientras que los otros están en lo cierto al decir que es imposible desconectarse de la autenticación HTTP básica, hay formas de implementar la autenticación que se comportan de manera similar. Una sugerencia obvia es usar auth_memcookie . Si realmente desea implementar la autenticación HTTP básica (es decir, use los diálogos del navegador para iniciar sesión en lugar de un formulario HTTP), simplemente establezca la autenticación en un directorio separado .htaccess protegido que contenga un script PHP que redireccione donde vino el usuario creando la sesión de Memcache.
Mu. No existe una forma correcta , ni siquiera una que sea coherente en todos los navegadores.
Este es un problema que proviene de la especificación HTTP (sección 15.6):
Los clientes y agentes de HTTP existentes normalmente retienen la información de autenticación indefinidamente. HTTP / 1.1. no proporciona un método para que un servidor ordene a los clientes que desechen estas credenciales en caché.
Por otro lado, la sección 10.4.2 dice:
Si la solicitud ya incluía credenciales de autorización, la respuesta 401 indica que se ha rechazado la autorización de esas credenciales. Si la respuesta 401 contiene el mismo desafío que la respuesta anterior, y el agente de usuario ya intentó la autenticación al menos una vez, entonces el usuario DEBERÍA presentar la entidad que se le dio en la respuesta, ya que esa entidad podría incluir información de diagnóstico relevante.
En otras palabras, es posible que pueda volver a mostrar el cuadro de inicio de sesión (como dice @Karsten ), pero el navegador no tiene que cumplir con su solicitud , por lo que no dependa demasiado de esta (mis) característica.
Necesitaba restablecer la autorización de .htaccess, así que usé esto:
<?php
if (!isset($_SERVER[''PHP_AUTH_USER''])) {
header(''WWW-Authenticate: Basic realm="My Realm"'');
header(''HTTP/1.0 401 Unauthorized'');
echo ''Text to send if user hits Cancel button'';
exit;
}
?>
Lo encontré aquí: http://php.net/manual/en/features.http-auth.php
Imagínate.
Varias soluciones residen en esa página e incluso se nota en la parte inferior: Lynx, no borra la autenticación como otros navegadores;)
Lo probé en mis navegadores instalados y, una vez cerrado, parece que cada navegador requiere repetidamente la reentrada.
Por lo general, una vez que un navegador le ha pedido al usuario las credenciales y las ha suministrado a un sitio web en particular, continuará haciéndolo sin necesidad de nuevas indicaciones. A diferencia de las diversas formas en que puede borrar las cookies en el lado del cliente, no conozco una manera similar de pedirle al navegador que olvide las credenciales de autenticación proporcionadas.
Tal vez estoy perdiendo el punto.
La forma más confiable que he encontrado para finalizar la Autenticación HTTP es cerrar el navegador y todas las ventanas del navegador. Puede cerrar una ventana del navegador usando Javascript, pero no creo que pueda cerrar todas las ventanas del navegador.
Trac - de forma predeterminada - también usa Autenticación HTTP. El cierre de sesión no funciona y no se puede arreglar:
- Este es un problema con el esquema de autenticación HTTP en sí mismo, y no hay nada que podamos hacer en Trac para repararlo correctamente.
- Actualmente no hay ninguna solución alternativa (JavaScript u otra) que funcione con todos los principales navegadores.
De: http://trac.edgewall.org/ticket/791#comment:103
Parece que no hay una respuesta operativa a la pregunta, ese problema se informó hace siete años y tiene perfecto sentido: HTTP es sin estado. O bien se realiza una solicitud con credenciales de autenticación o no. Pero eso es una cuestión de que el cliente envíe la solicitud, no el servidor que la recibe. El servidor solo puede decir si un URI de solicitud necesita autorización o no.
Solución (no es una solución limpia, agradable (¡o incluso funciona! Ver comentarios)):
Inhabilita sus credenciales una vez.
Puede mover su lógica de autenticación HTTP a PHP enviando los encabezados apropiados (si no está conectado):
Header(''WWW-Authenticate: Basic realm="protected area"'');
Header(''HTTP/1.0 401 Unauthorized'');
Y analizando la entrada con:
$_SERVER[''PHP_AUTH_USER''] // httpauth-user
$_SERVER[''PHP_AUTH_PW''] // httpauth-password
Por lo tanto, deshabilitar sus credenciales una vez debería ser trivial.
Solución
Puedes hacer esto usando Javascript:
<html><head>
<script type="text/javascript">
function logout() {
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
// code for IE
else if (window.ActiveXObject) {
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
if (window.ActiveXObject) {
// IE clear HTTP Authentication
document.execCommand("ClearAuthenticationCache");
window.location.href=''/where/to/redirect'';
} else {
xmlhttp.open("GET", ''/path/that/will/return/200/OK'', true, "logout", "logout");
xmlhttp.send("");
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {window.location.href=''/where/to/redirect'';}
}
}
return false;
}
</script>
</head>
<body>
<a href="#" onclick="logout();">Log out</a>
</body>
</html>
Lo que se hace arriba es:
para IE : simplemente borre la caché de autenticación y redirija a algún lado
para otros navegadores : envíe un XMLHttpRequest detrás de escena con el nombre de inicio de sesión y la contraseña de "cierre de sesión". Necesitamos enviarlo a alguna ruta que devolverá 200 OK a esa solicitud (es decir, no debería requerir autenticación HTTP).
Reemplace ''/where/to/redirect''
con alguna ruta para redirigir a después de cerrar la sesión y reemplace ''/path/that/will/return/200/OK''
con alguna ruta en su sitio que devolverá 200 OK.