通过PHP的HTTPauthentication注销

什么是注销HTTP身份validation保护的文件夹的正确方法?

有解决方法可以实现这一点,但它们有潜在的危险,因为它们可能是有问题的,或者在某些情况/浏览器中不起作用。 这就是为什么我正在寻找正确和干净的解决scheme。

亩。 没有正确的方法存在 ,甚至没有一个在浏览器中是一致的。

这是来自HTTP规范 (第15.6节)的问题:

现有的HTTP客户端和用户代理通常无限期地保留authentication信息。 HTTP / 1.1。 不提供服务器的方法来指示客户端放弃这些caching的凭据。

另一方面,第10.4.2节说:

如果请求已经包含了授权凭证,那么401响应表明这些凭证的授权已被拒绝。 如果401响应包含与之前的响应相同的挑战,并且用户代理已经尝试了至less一次authentication,则用户应该被呈现给响应中给出的实体,因为该实体可能包括相关的诊断信息。

换句话说, 你可能会再次显示login框 (就像@ Karsten说的), 但是浏览器不必遵守你的请求 – 所以不要太依赖这个(错误)function。

在Safari中很好地工作的方法。 也适用于Firefox和Opera,但有警告。

 Location: http://logout@yourserver.example.com/ 

这告诉浏览器用新的用户名打开URL,覆盖以前的用户名。

简单的答案是你不能可靠地注销httpauthentication。

漫长的回答:
Http-auth(就像HTTP规范的其余部分)是无状态的。 所以“login”或“注销”并不是一个真正有意义的概念。 更好的方法是查询每个HTTP请求(并记住一个页面加载通常是多个请求),“你可以做你正在请求的东西吗?”。 服务器将每个请求视为新的请求,并且与之前的请求无关。

浏览器已经select记住第一个401上告诉他们的凭证,并在未经用户明确许可的情况下重新发送。 这是为了向用户提供他们期望的“login/注销”模式,但这纯粹是一种混乱。 这是模拟这种持久状态的浏览器 。 Web服务器完全不知道它。

所以在http-auth的上下文中“注销”纯粹是由浏览器提供的模拟,所以在服务器的权限之外。

是的,有一些杂物。 但是它们破坏了RESTfulness(如果这对你有价值)并且它们是不可靠的。

如果你绝对需要一个login/注销的模式进行站点身份validation,最好的办法就是跟踪cookie,以某种方式(mysql,sqlite,flatfile等)在服务器上存储状态持久性。 这将需要评估所有请求,例如,用PHP。

解决方法

你可以使用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> 

以上所做的是:

  • 对于IE – 只需清除身份validationcaching并redirect到某个地方

  • 对于其他浏览器 – 使用“注销”login名和密码在幕后发送XMLHttpRequest。 我们需要将它发送到某个path,该path将返回200 OK(即,它不应该要求HTTPauthentication)。

在注销之后,将'/where/to/redirect'replace为redirect到的某个path,并将您的站点上的某个pathreplace为'/path/that/will/return/200/OK' ,返回200 OK。

解决方法 (不是一个干净的,不错的(甚至是工作!见解)解决scheme):

禁用他的凭据一次。

您可以通过发送适当的头文件(如果没有login)将您的HTTPauthentication逻辑移动到PHP:

 Header('WWW-Authenticate: Basic realm="protected area"'); Header('HTTP/1.0 401 Unauthorized'); 

并分析input:

 $_SERVER['PHP_AUTH_USER'] // httpauth-user $_SERVER['PHP_AUTH_PW'] // httpauth-password 

所以一次禁用他的凭证应该是微不足道的。

从HTTP基本身份validation分两步注销

比方说,我有一个名为“密码保护”的HTTP基本身份validation领域,鲍勃login。注销我做了2个AJAX请求:

  1. 访问脚本/ logout_step1。 它将一个随机临时用户添加到.htusers,并以其login名和密码进行响应。
  2. 访问脚本/ logout_step2 使用临时用户的login名和密码进行身份validation 。 该脚本删除临时用户,并在响应中添加以下标题: WWW-Authenticate: Basic realm="Password protected"

此时浏览器忘记了Bob的凭据。

我对这个问题的解决方法如下。 你可以在这个页面的第二个例子中find函数http_digest_parse$realm$users : 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; } 

通常情况下,一旦浏览器向用户询问凭证并将其提供给特定网站,它将继续这样做而不会进一步提示。 与您可以在客户端清除Cookie的各种方式不同,我不知道类似的方式来要求浏览器忘记提供的身份validation凭据。

Trac – 默认情况下也使用HTTP身份validation。 注销不起作用,不能修复:

  • 这是HTTP身份validationscheme本身的一个问题,我们没有办法在Trac中正确解决这个问题。
  • 目前没有解决方法(JavaScript或其他),适用于所有主stream浏览器。

来自: http : //trac.edgewall.org/ticket/791#comment : 103

看起来这个问题没有任何可行的答案,这个问题已经在七年前被报道过了,而且非常有意义:HTTP是无状态的。 要么使用身份validation凭证完成请求。 但是这是客户端发送请求的问题,而不是服务器接收请求的问题。 服务器只能说一个请求URI是否需要授权。

我需要重置.htaccess授权,所以我用这个:

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

在这里find它: http : //php.net/manual/en/features.http-auth.php

去搞清楚。

许多解决scheme驻留在该页面上,甚至在底部注释:Lynx,不像其他浏览器那样清除auth;)

我在已安装的浏览器上testing过,一旦closures,每个浏览器似乎总是需要重新inputreuth。

这可能不是被期待的解决scheme,但我解决这个问题。 我有2个脚本的注销过程。

logout.php

 <?php header("Location: http://.@domain.com/log.php"); ?> 

log.php

 <?php header("location: https://google.com"); ?> 

这样我没有得到一个警告,我的会议终止

AFAIK,当使用htaccess(即基于HTTP)authentication时,没有干净的方法来实现“注销”function。

这是因为这种身份validation使用HTTP错误代码“401”来告诉浏览器需要凭据,此时浏览器会提示用户提供详细信息。 从此以后,直到浏览器closures,它将始终发送凭据而不会进一步提示。

到目前为止我发现的最好的解决scheme是(这是一种伪代码, $isLoggedIn是http auth的伪variables):

在“登出”的时候,只是将一些信息存储到会话中,说用户实际上已经注销了。

 function logout() { //$isLoggedIn = false; //This does not work (point of this question) $_SESSION['logout'] = true; } 

在我检查身份validation的地方,我扩大了条件:

 function isLoggedIn() { return $isLoggedIn && !$_SESSION['logout']; } 

会话与httpauthentication的状态有一定的联系,所以只要浏览器保持打开状态,只要httpauthentication持续存在,用户就可以保持注销。

虽然其他人说是不可能从基本的HTTP身份validation注销是正确的,有办法实现authentication行为相似。 一个明显的附件是使用auth_memcookie 。 如果你真的想实现基本的HTTP身份validation(即使用浏览器对话框来loggingHTTPforms),只需将身份validation设置为一个单独的.htaccess受保护的包含PHP脚本的目录,该脚本将redirect回到用户所在的位置创buildmemcache会话。

也许我错过了这一点。

我发现结束HTTP身份validation的最可靠的方法是closures浏览器和所有浏览器窗口。 您可以使用JavaScriptclosures浏览器窗口,但我不认为您可以closures所有的浏览器窗口。

这里有很多很复杂的答案。 在我的具体情况下,我发现一个干净和简单的修复注销。 我还没有在Edgetesting。 在我已login的页面上,我已经放置了一个类似如下的注销链接:

 <a href="https://MyDomainHere.net/logout.html">logout</a> 

并且在那个logout.html页面的头部(也被.htaccess保护),我有一个类似这样的页面刷新:

 <meta http-equiv="Refresh" content="0; url=https://logout:logout@MyDomainHere.net/" /> 

在那里你会留下“注销”的话来清除caching的网站的用户名和密码。

我承认,如果多个页面需要能够从头开始直接login,那么每个input点都需要他们自己对应的logout.html页面。 否则,您可以通过在实际login提示之前引入额外的守门人步骤来集中注销,要求input短语以到达login目的地。

我发现消灭PHP_AUTH_DIGESTPHP_AUTH_USERPHP_AUTH_PW凭证的唯一有效方法是调用头部HTTP/1.1 401 Unauthorized

 function clear_admin_access(){ header('HTTP/1.1 401 Unauthorized'); die('Admin access turned off'); }