注销HTTP身份验证受保护的文件夹的正确方法是什么?
有一些解决方法可以实现此目的,但它们可能会带来危险,因为它们可能有故障或在某些情况/浏览器中无法使用。这就是为什么我要寻找正确和清洁的解决方案。
Miscellaneous -> Clear Private Data -> HTTP Authentication
注销HTTP身份验证受保护的文件夹的正确方法是什么?
有一些解决方法可以实现此目的,但它们可能会带来危险,因为它们可能有故障或在某些情况/浏览器中无法使用。这就是为什么我要寻找正确和清洁的解决方案。
Miscellaneous -> Clear Private Data -> HTTP Authentication
Answers:
亩。没有正确的方法存在,甚至没有跨浏览器一致的方法。
这是来自HTTP规范(第15.6节)的问题:
现有的HTTP客户端和用户代理通常会无限期地保留身份验证信息。HTTP / 1.1。没有为服务器提供一种方法来指示客户端丢弃这些缓存的凭据。
另一方面,第10.4.2节说:
如果请求已包含授权凭据,则401响应指示已拒绝这些凭据的授权。如果401响应包含与先前响应相同的质询,并且用户代理已经尝试了至少一次身份验证,则应该向用户提供响应中给定的实体,因为该实体可能包括相关的诊断信息。
换句话说,您也许可以再次显示登录框(如@Karsten所说),但是浏览器不必满足您的请求 -因此,不要过多地依赖此功能。
在Safari中效果很好的方法。在Firefox和Opera中也可以使用,但带有警告。
Location: http://logout@yourserver.example.com/
这告诉浏览器使用新的用户名打开URL,覆盖新的用户名。
user:password@host
已弃用。仅使用http://logout@yourserver.example.com/
不是,并且在大多数情况下应该可以使用。
简单的答案是您不能可靠地注销http身份验证。
长答案:
Http-auth(与HTTP规范的其余部分一样)是无状态的。因此,“登录”或“注销”并不是一个有意义的概念。看到它的更好的方法是针对每个HTTP请求(记住页面加载通常是多个请求)询问“是否允许您执行请求的操作?”。服务器将每个请求视为新请求,并且与以前的任何请求都不相关。
浏览器已选择记住您在第一个401上告诉他们的凭据,然后在没有用户对后续请求的明确许可的情况下重新发送它们。这是为用户提供他们期望的“已登录/已注销”模型的尝试,但这纯粹是一种错误。正是浏览器在模拟这种状态的持久性。Web服务器完全不知道它。
因此,在http-auth上下文中,“注销”纯粹是由浏览器提供的模拟,因此不在服务器权限范围内。
是的,有仇。但是它们破坏了RESTful-ness(如果这对您来说很有价值),并且它们不可靠。
如果您绝对需要登录/注销模型来进行站点认证,那么最好的选择是跟踪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-只需清除身份验证缓存并重定向到某处
对于其他浏览器 -在后台使用“注销”登录名和密码发送XMLHttpRequest。我们需要将其发送到某个路径,该路径将对该请求返回200 OK(即,它不需要HTTP身份验证)。
更换'/where/to/redirect'
一些路径注销后重定向到并替换'/path/that/will/return/200/OK'
与您网站上的一些路径,将返回200 OK。
解决方法(不是一个干净的,不错的(甚至无法工作!请参见评论)解决方案):
一次禁用他的凭据。
您可以通过发送适当的标头(如果未登录)将HTTP身份验证逻辑移至PHP:
Header('WWW-Authenticate: Basic realm="protected area"');
Header('HTTP/1.0 401 Unauthorized');
并使用以下命令解析输入:
$_SERVER['PHP_AUTH_USER'] // httpauth-user
$_SERVER['PHP_AUTH_PW'] // httpauth-password
因此,一次禁用他的凭据应该是微不足道的。
假设我有一个名为“密码保护”的HTTP基本身份验证领域,Bob已登录。要注销,我发出2个AJAX请求:
WWW-Authenticate: Basic realm="Password protected"
此时,浏览器忘记了Bob的凭据。
我对这个问题的解决方法如下。您可以找到该函数http_digest_parse
,$realm
并且$users
在此页面的第二个示例中:http : //php.net/manual/zh/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的各种方法不同,我不知道有类似的方法要求浏览器忘记其提供的身份验证凭据。
Trac(默认情况下)也使用HTTP身份验证。注销不起作用,无法解决:
- 这是HTTP身份验证方案本身的问题,在Trac中我们无法采取任何措施来正确修复它。
- 当前尚没有适用于所有主要浏览器的解决方法(JavaScript或其他)。
来自: http : //trac.edgewall.org/ticket/791#comment : 103
看起来该问题没有有效的答案,该问题已在7年前报告过,这很有意义:HTTP是无状态的。是否使用身份验证凭据来完成请求。但这是客户端发送请求的问题,而不是服务器接收请求的问题。服务器只能说出请求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;
}
?>
在这里找到它:http : //php.net/manual/en/features.http-auth.php
去搞清楚。
该页面上有很多解决方案,甚至在底部都有说明:Lynx,不会像其他浏览器一样清除auth;)
我在已安装的浏览器上对其进行了测试,并且关闭后,每个浏览器似乎始终需要在重新输入时进行重新验证。
WWW-Authenticate
导致问题的信息,自动删除导致我退出的信息。
WWW-Authenticate
通知会导致另一浏览器(Firefox)记住凭据,并在下一个请求时发送凭据,从而导致自动重新登录!啊!
这可能不是寻找的解决方案,但我这样解决了。我有2个脚本用于注销过程。
logout.php
<?php
header("Location: http://.@domain.com/log.php");
?>
log.php
<?php
header("location: https://google.com");
?>
这样,我不会收到警告,并且会话会终止
到目前为止,我发现的最佳解决方案是(这是一种伪代码, $isLoggedIn
http auth的伪变量):
在“注销”时,只需将一些信息存储到会话中即可表明该用户实际上已注销。
function logout()
{
//$isLoggedIn = false; //This does not work (point of this question)
$_SESSION['logout'] = true;
}
在我检查身份验证的地方,我扩展了条件:
function isLoggedIn()
{
return $isLoggedIn && !$_SESSION['logout'];
}
会话在某种程度上与http身份验证的状态相关联,因此,只要用户保持浏览器打开以及http身份验证在浏览器中持续存在,用户就保持注销状态。
也许我错过了重点。
我发现结束HTTP身份验证的最可靠方法是关闭浏览器和所有浏览器窗口。您可以使用Javascript关闭浏览器窗口,但我认为您无法关闭所有浏览器窗口。
当其他人在说,是正确的它不可能从基本的HTTP认证注销有实现其认证的方式表现相似。一种明显的方法是使用auth_memcookie。如果您确实想使用此方法来实现基本的HTTP身份验证(即使用浏览器对话框登录而不是HTTP形式),只需将身份验证设置为一个单独的.htaccess保护目录,其中包含一个PHP脚本,该脚本会将用户重定向到后面的位置创建内存缓存会话。
这里有很多很棒的-复杂的-答案。在我的特殊情况下,我找到了一个干净而简单的注销解决方法。我尚未在Edge中进行测试。在我登录的页面上,放置了一个类似于以下内容的注销链接:
<a href="https://MyDomainHere.net/logout.html">logout</a>
在该logout.html页面(也受.htaccess保护)的顶部,我有一个类似于以下内容的页面刷新:
<meta http-equiv="Refresh" content="0; url=https://logout:logout@MyDomainHere.net/" />
您将在其中保留“注销”字样的位置,以清除为站点缓存的用户名和密码。
我将承认,如果需要从一开始就可以直接登录多个页面,那么每个入口点都将需要它们自己的相应logout.html页面。否则,您可以通过在实际登录提示之前在过程中引入一个额外的网守步骤来集中注销,这需要输入短语才能到达登录目标。