通过PHP实现HTTP身份验证注销

158

如何正确地退出HTTP身份验证保护文件夹?

虽然有一些方法可以实现这一点,但它们潜在的危险性很高,因为它们可能存在漏洞或在某些情况/浏览器中无法工作。这就是为什么我正在寻找正确而干净的解决方案。


请说明您注销的目的。这应该是强制注销(用户停用)吗?还是仅为用户提供简单的注销功能?还有其他需要考虑的吗? - Karsten
6
我不明白为什么这很重要,但它包括两种情况:基于应用内部条件的停用和常规的注销按钮。请解释一下为什么它很重要,我会直接将答案编辑到问题中。 - Josef Sábl
2
“正确而干净的解决方案”是浏览器拥有自己的注销按钮,当单击该按钮时,浏览器将停止发送Auth标头...一个人可以做梦,对吧? - DanMan
1
Web开发者工具栏有这样的“按钮”。 - Josef Sábl
Josef说的是:Firefox网页开发者工具栏 -> 杂项 -> 清除私人数据 -> HTTP身份验证 - Yarin
19个回答

2

我需要重置.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不像其他浏览器一样清除授权;) 我在我的安装的浏览器上测试过,一旦关闭,每个浏览器似乎都需要重新输入授权信息才能再次进入。

这似乎不起作用,我收到了取消文本,但没有弹出登录框。 - Michael
结果发现,发送 WWW-Authenticate 导致了问题,去掉它后自动注销了我。 - Michael
反之,似乎在修复一个浏览器(Chrome)中的问题时发送“WWW-Authenticate”会导致另一个浏览器(Firefox)记住凭据并在下一次请求中发送它们,从而导致自动重新登录! 哎呀! - Michael
然后查看UA并执行其中之一似乎是一个解决方案。 - Mr. Developerdude

2
这可能不是你要寻找的解决方案,但我是这样解决的。我有两个脚本用于注销过程。 logout.php
<?php
header("Location: http://.@domain.com/log.php");
?>

log.php

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

这样我就不会收到警告并且我的会话被终止。

1
这真的是唯一对我有效的解决方案!在Firefox 37和Chromium 41上进行了测试。 - zesaver

1
也许我没有理解重点。
我发现最可靠的方法是关闭浏览器和所有浏览器窗口来结束HTTP身份验证。您可以使用Javascript关闭浏览器窗口,但我认为您无法关闭所有浏览器窗口。

FYI,一些浏览器如果只有一个标签页是打开的,那么它们将无法关闭窗口,所以这个观点实际上是无关紧要的。 - scape
那些年,我有一个任务要实现注销按钮而不关闭窗口 :-) 但也许他们不会纠结于“不关闭窗口”。但是嘿,这是一个简单的解决方案,可能对某些人有效,而当时我错过了它,说实话。 - Josef Sábl

1
据我所知,在使用htaccess(即基于HTTP的)身份验证时,没有干净的方法来实现“注销”功能。
这是因为此类身份验证使用HTTP错误代码“401”告诉浏览器需要凭据,此时浏览器提示用户输入详细信息。从那时起,直到关闭浏览器为止,它将始终发送凭据而无需进一步提示。

1
到目前为止我找到的最好的解决方案是(这是一种伪代码,$isLoggedIn 是用于 HTTP 认证的伪变量):
在“注销”时,只需将一些信息存储到会话中,说明用户实际上已经注销了。
function logout()
{
  //$isLoggedIn = false; //This does not work (point of this question)
  $_SESSION['logout'] = true;
}

在我检查身份验证的地方,我扩展了条件:
function isLoggedIn()
{
  return $isLoggedIn && !$_SESSION['logout'];
}

Session(会话)与http认证的状态有一定关联,因此只要用户保持浏览器打开并且http认证在浏览器中继续存在,用户就会一直保持注销状态。


4
虽然HTTP基本身份验证是符合RESTful标准的,但会话并不符合。 - deamon

0

我在一篇文章中总结了我的解决方案(https://www.hattonwebsolutions.co.uk/articles/how_to_logout_of_http_sessions),但是我使用了一个ajax调用和2个htaccess文件(如此问题所建议的:How to logout of an HTTP authentication (htaccess) that works in Google Chrome?)。

简而言之,你需要:

  1. 创建一个具有相同AuthName但需要不同用户的htaccess文件的子文件夹
  2. 向页面发送一个ajax请求(使用错误的用户名)(失败后)并触发超时重定向到已注销的页面。

这避免了在注销文件夹中有一个次要弹出窗口请求另一个用户名(这会使用户感到困惑)。我的文章使用了Jquery,但应该可以避免使用它。


0

虽然其他人说从基本的HTTP身份验证注销是不可能的,但有办法实现类似的身份验证。一个明显的方法是使用auth_memcookie。如果你真的想要实现基本的HTTP身份验证(即使用浏览器对话框进行登录而不是HTTP表单),只需将身份验证设置为一个单独的.htaccess受保护目录,其中包含一个PHP脚本,该脚本在创建memcache会话后重定向回用户来的地方。


0

我通过发送401头部信息来实现这个功能。使用PHP可以很好地完成。

header('HTTP/1.0 401 Unauthorized');

0

这里有很多伟大而复杂的答案。在我的情况下,我找到了一个简单明了的解决方案来注销。我还没有在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页面。否则,您可以通过在实际登录提示之前引入一个额外的关卡步骤来集中注销过程,要求输入短语以到达登录目的地。


1
当向前移动时,这个程序可以正常工作并且能够注销,但是浏览器的后退历史记录仍然可以重新建立会话。 - johnwayne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接