通过 PHP 进行 HTTP 身份验证注销

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/449788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 22:46:38  来源:igfitidea点击:

HTTP authentication logout via PHP

phpauthentication.htaccesshttp-headerspassword-protection

提问by Josef Sábl

What is the correctway to log out of HTTP authentication protected folder?

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

There are workarounds that can achieve this, but they are potentially dangerous because they can be buggy or don't work in certain situations / browsers. That is why I am looking for correct and clean solution.

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

采纳答案by Piskvor left the building

Mu. No correct way exists, not even one that's consistent across browsers.

亩。不存在正确的方法,甚至没有一种跨浏览器一致的方法。

This is a problem that comes from the HTTP specification(section 15.6):

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

Existing HTTP clients and user agents typically retain authentication information indefinitely. HTTP/1.1. does not provide a method for a server to direct clients to discard these cached credentials.

现有的 HTTP 客户端和用户代理通常会无限期地保留身份验证信息。HTTP/1.1。不为服务器提供一种方法来指示客户端丢弃这些缓存的凭据。

On the other hand, section 10.4.2says:

另一方面,第10.4.2节说:

If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information.

如果请求已包含授权凭据,则 401 响应指示对这些凭据的授权已被拒绝。如果 401 响应包含与先前响应相同的质询,并且用户代理至少已经尝试过一次身份验证,那么应该向用户呈现响应中给出的实体,因为该实体可能包含相关的诊断信息。

In other words, you may be able to show the login box again(as @Karstensays), but the browser doesn't have to honor your request- so don't depend on this (mis)feature too much.

换句话说,您可以再次显示登录框(如@Karsten所说),但浏览器不必满足您的请求- 所以不要过分依赖此(错误)功能。

回答by Kornel

Method that works nicely in Safari. Also works in Firefox and Opera, but with a warning.

在 Safari 中运行良好的方法。也适用于 Firefox 和 Opera,但有警告。

Location: http://[email protected]/

This tells browser to open URL with new username, overriding previous one.

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

回答by Jonathan Hanson

The simple answer is that you can't reliably log out of http-authentication.

简单的答案是您无法可靠地注销 http 身份验证。

The long answer:
Http-auth (like the rest of the HTTP spec) is meant to be stateless. So being "logged in" or "logged out" isn't really a concept that makes sense. The better way to see it is to ask, for each HTTP request (and remember a page load is usually multiple requests), "are you allowed to do what you're requesting?". The server sees each request as new and unrelated to any previous requests.

长答案:
Http-auth(就像 HTTP 规范的其余部分一样)是无状态的。因此,“登录”或“注销”并不是一个真正有意义的概念。查看它的更好方法是询问每个 HTTP 请求(并记住页面加载通常是多个请求),“您是否允许执行您请求的操作?”。服务器将每个请求视为新请求,并且与之前的任何请求无关。

Browsers have chosen to remember the credentials you tell them on the first 401, and re-send them without the user's explicit permission on subsequent requests. This is an attempt at giving the user the "logged in/logged out" model they expect, but it's purely a kludge. It's the browserthat's simulating this persistence of state. The web server is completely unaware of it.

浏览器选择记住你在第一个 401 时告诉他们的凭据,并在没有用户明确许可的情况下重新发送它们对后续请求。这是为用户提供他们期望的“登录/注销”模型的尝试,但这纯粹是胡说八道。正是浏览器模拟了这种状态的持久性。Web 服务器完全不知道它。

So "logging out", in the context of http-auth is purely a simulation provided by the browser, and so outside the authority of the server.

所以“登出”,在http-auth上下文中纯粹是浏览器提供的模拟,所以不在服务器的权限范围内。

Yes, there are kludges. But they break RESTful-ness (if that's of value to you) and they are unreliable.

是的,有杂物。但是它们破坏了 RESTful 性(如果这对您有价值)并且它们不可靠。

If you absolutely require a logged-in/logged-out model for your site authentication, the best bet is a tracking cookie, with the persistence of state stored on the server in some manner (mysql, sqlite, flatfile, etc). This will require all requests to be evaluated, for instance, with PHP.

如果您绝对需要登录/注销模型来进行站点身份验证,最好的选择是跟踪 cookie,并以某种方式(mysql、sqlite、flatfile 等)将状态持久性存储在服务器上。这将需要评估所有请求,例如,使用 PHP。

回答by Anton Mochalin

Workaround

解决方法

You can do this using Javascript:

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

What is done above is:

上面所做的是:

  • for IE- just clear auth cache and redirect somewhere

  • for other browsers- send an XMLHttpRequest behind the scenes with 'logout' login name and password. We need to send it to some path that will return 200 OK to that request (i.e. it shouldn't require HTTP authentication).

  • 对于 IE- 只需清除身份验证缓存并重定向到某个地方

  • 对于其他浏览器- 在幕后发送带有“注销”登录名和密码的 XMLHttpRequest。我们需要将它发送到某个路径,该路径将为该请求返回 200 OK(即它不应该需要 HTTP 身份验证)。

Replace '/where/to/redirect'with some path to redirect to after logging out and replace '/path/that/will/return/200/OK'with some path on your site that will return 200 OK.

更换'/where/to/redirect'一些路径注销后重定向到并替换'/path/that/will/return/200/OK'与您网站上的一些路径,将返回200 OK。

回答by Karsten

Workaround(not a clean, nice (or even working! see comments) solution):

解决方法(不是一个干净、漂亮(甚至工作!见评论)的解决方案):

Disable his credentials one time.

禁用他的凭据一次。

You can move your HTTP authentication logic to PHP by sending the appropriate headers (if not logged in):

您可以通过发送适当的标头(如果未登录)将 HTTP 身份验证逻辑移至 PHP:

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

And parsing the input with:

并解析输入:

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

So disabling his credentials one time should be trivial.

因此,一次禁用他的凭据应该是微不足道的。

回答by Pie86

My solution to the problem is the following. You can find the function http_digest_parse, $realmand $usersin the second example of this page: http://php.net/manual/en/features.http-auth.php.

我对这个问题的解决方案如下。你可以找到的功能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;
}

回答by Vlad GURDIGA

Logout from HTTP Basic Auth in two steps

分两步从 HTTP Basic Auth 注销

Let's say I have a HTTP Basic Auth realm named “Password protected”, and Bob is logged in. To log out I make 2 AJAX requests:

假设我有一个名为“密码保护”的 HTTP 基本身份验证领域,并且 Bob 已登录。为了注销,我发出了 2 个 AJAX 请求:

  1. Access script /logout_step1. It adds a random temporary user to .htusers and responds with its login and password.
  2. Access script /logout_step2 authenticated with the temporary user's login and password. The script deletes the temporary user and adds this header on the response: WWW-Authenticate: Basic realm="Password protected"
  1. 访问脚本 /logout_step1。它将随机临时用户添加到 .htusers 并使用其登录名和密码进行响应。
  2. 使用临时用户的登录名和密码进行身份验证的访问脚本 /logout_step2 。该脚本删除临时用户并在响应中添加此标头:WWW-Authenticate: Basic realm="Password protected"

At this point browser forgot Bob's credentials.

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

回答by Greg Hewgill

Typically, once a browser has asked the user for credentials and supplied them to a particular web site, it will continue to do so without further prompting. Unlike the various ways you can clear cookies on the client side, I don't know of a similar way to ask the browser to forget its supplied authentication credentials.

通常,一旦浏览器要求用户提供凭据并将其提供给特定网站,它就会继续这样做,而无需进一步提示。与您可以在客户端清除 cookie 的各种方法不同,我不知道有什么类似的方法可以让浏览器忘记其提供的身份验证凭据。

回答by hakre

Trac - by default - uses HTTP Authentication as well. Logout does not work and can not be fixed:

Trac - 默认情况下 - 也使用 HTTP 身份验证。注销不起作用,无法修复:

  • This is an issue with the HTTP authentication scheme itself, and there's nothing we can do in Trac to fix it properly.
  • There is currently no workaround (JavaScript or other) that works with all major browsers.
  • 这是 HTTP 身份验证方案本身的问题,我们在 Trac 中无法正确修复它。
  • 目前没有适用于所有主要浏览器的解决方法(JavaScript 或其他)。

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

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

Looks like that there is no working answer to the question, that issue has been reported seven years ago and it makes perfect sense: HTTP is stateless. Either a request is done with authentication credentials or not. But that's a matter of the client sending the request, not the server receiving it. The server can only say if a request URI needs authorization or not.

看起来这个问题没有有效的答案,这个问题已经在七年前被报道过,而且完全有道理:HTTP 是无状态的。请求是否使用身份验证凭据完成。但这是客户端发送请求的问题,而不是接收请求的服务器。服务器只能说明请求 URI 是否需要授权。

回答by Dooley

I needed to reset .htaccess authorization so I used this:

我需要重置 .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;
}
?>

Found it here : http://php.net/manual/en/features.http-auth.php

在这里找到:http: //php.net/manual/en/features.http-auth.php

Go figure.

去搞清楚。

A number of solutions reside on that page and it even notes at the bottom: Lynx, doesn't clear the auth like other browsers ;)

许多解决方案驻留在该页面上,它甚至在底部注明:Lynx,不像其他浏览器那样清除身份验证;)

I tested it out on my installed browsers and once closed, each browser seems like it consistently requires reauth on reentry.

我在已安装的浏览器上对其进行了测试,一旦关闭,每个浏览器似乎都需要在重新进入时重新进行身份验证。