如何正确地退出HTTP身份验证保护文件夹?
虽然有一些方法可以实现这一点,但它们潜在的危险性很高,因为它们可能存在漏洞或在某些情况/浏览器中无法工作。这就是为什么我正在寻找正确而干净的解决方案。
如何正确地退出HTTP身份验证保护文件夹?
虽然有一些方法可以实现这一点,但它们潜在的危险性很高,因为它们可能存在漏洞或在某些情况/浏览器中无法工作。这就是为什么我正在寻找正确而干净的解决方案。
Mu. 没有正确的方法存在,甚至没有一种方法可以在所有浏览器上保持一致。
这个问题来自于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/
在大多数情况下可以正常工作。 - aef解决方案
您可以使用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_digest_parse
,$realm
和$users
:http://php.net/manual/en/features.http-auth.php。请注意,保留了HTML标签。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;
}
假设我有一个名为“密码保护”的HTTP基本认证领域,并且Bob已经登录。要退出,我需要进行2个AJAX请求:
WWW-Authenticate: Basic realm="Password protected"
此时浏览器忘记了Bob的凭据。
我发现清除PHP_AUTH_DIGEST
或PHP_AUTH_USER
和PHP_AUTH_PW
凭据的唯一有效方法是调用头文件HTTP/1.1 401 Unauthorized
。
function clear_admin_access(){
header('HTTP/1.1 401 Unauthorized');
die('Admin access turned off');
}
通常,一旦浏览器要求用户提供凭据并将其提供给特定网站,它将继续这样做而不需要进一步提示。与您可以在客户端清除 cookie 的各种方式不同,我不知道有类似的方法可以要求浏览器忘记其提供的身份验证凭据。
默认情况下,Trac也使用HTTP身份验证。注销无法正常工作,也无法修复:
- 这是HTTP身份验证机制本身的问题,我们在Trac中无法进行适当的修复。
- 目前没有任何解决方法(JavaScript或其他),适用于所有主流浏览器。
来自:http://trac.edgewall.org/ticket/791#comment:103
看起来似乎没有对这个问题的有效答案,这个问题已经报告了七年,这是有道理的:HTTP是无状态的。请求要么带有身份验证凭据,要么没有。但这取决于客户端发送请求,而不是服务器接收请求。服务器只能说明请求URI是否需要授权。
杂项 -> 清除私人数据 -> HTTP身份验证
- Yarin