代码之家  ›  专栏  ›  技术社区  ›  Josef Sábl

通过PHP注销HTTP身份验证

  •  147
  • Josef Sábl  · 技术社区  · 16 年前

    什么是 对的 退出HTTP身份验证保护文件夹的方法?

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

    17 回复  |  直到 7 年前
        1
  •  102
  •   Community Marino Di Clemente    7 年前

    亩。 不存在正确的方法 ,甚至不是在浏览器中保持一致的。

    这是一个来自 HTTP specification (第15.6节):

    现有的HTTP客户端和用户代理通常保留身份验证 信息无限期。http/ 1.1。不提供用于 服务器指示客户端放弃这些缓存的凭据。

    另一方面,节 10.4.2 说:

    如果请求已经包含授权凭据,则401 响应表示已拒绝这些授权 资格证书。如果401响应包含与 先前的响应,用户代理已尝试 身份验证至少一次,然后应向用户显示 响应中给出的实体,因为该实体可能 包括相关诊断信息。

    换言之, 您可以再次显示登录框 (AS) @Karsten 说) 但浏览器不必满足您的要求 -所以不要太依赖这个(MIS)特性。

        2
  •  57
  •   Kornel    12 年前

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

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

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

        3
  •  43
  •   Jonathan Hanson    14 年前

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

    答案很长:
    HTTP认证(和HTTP规范的其余部分一样)是无状态的。所以“登录”或“注销”并不是一个有意义的概念。更好的方法是,对于每个HTTP请求(记住一个页面加载通常是多个请求),询问“您允许执行您请求的操作吗?”。服务器将每个请求视为新请求,与以前的任何请求都无关。

    浏览器已经选择记住您在第一个401中告诉他们的凭证,并在没有用户对后续请求明确许可的情况下重新发送它们。这是一个试图给用户提供他们所期望的“登录/注销”模型的尝试,但这纯粹是一个拼凑。这是 浏览器 这是在模拟这种状态的持久性。Web服务器完全不知道这一点。

    因此,在HTTP身份验证的上下文中,“注销”纯粹是由浏览器提供的模拟,因此超出了服务器的权限。

    是的,有很多拼图。但是他们打破了宁静(如果这对你有价值的话),他们是不可靠的。

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

        4
  •  25
  •   nickhar    12 年前

    解决办法

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

        5
  •  13
  •   Chris Wesseling    13 年前

    解决办法 (不是一个干净,漂亮的(甚至是工作的)!请参见注释)解决方案):

    一次禁用他的证书。

    通过发送适当的头(如果未登录),可以将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
    

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

        6
  •  7
  •   Vlad GURDIGA    12 年前

    通过两个步骤从HTTP基本身份验证注销

    假设我有一个名为__password protected__的HTTP基本认证领域,Bob已登录。要注销,我会发出2个Ajax请求:

    1. 访问脚本/注销步骤1。它向.htusers添加一个随机的临时用户,并用其登录名和密码进行响应。
    2. 访问脚本/注销步骤2 authenticated with the temporary user’s login and password . 脚本将删除临时用户,并将此头添加到响应中: WWW-Authenticate: Basic realm="Password protected"

    此时,浏览器忘记了Bob_的凭证。

        7
  •  7
  •   Pie86    11 年前

    我的解决方案如下。你可以找到这个函数 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;
    }
    
        8
  •  4
  •   Greg Hewgill    16 年前

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

        9
  •  2
  •   hakre    13 年前

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

    • 这是HTTP认证方案本身的一个问题,在TRAC中我们不能做任何事情来正确地修复它。
    • 目前没有适用于所有主要浏览器的解决方案(javascript或其他)。

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

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

        10
  •  2
  •   Dooley    13 年前

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

    我在我安装的浏览器上测试了它,一旦关闭,每一个浏览器似乎都需要重新授权才能重新进入。

        11
  •  2
  •   Kevin    9 年前

    这可能不是我们寻找的解决方案,但我是这样解决的。 我有两个注销过程脚本。

    注解

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

    PHP

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

    这样我就不会收到警告,我的会话也会终止。

        12
  •  1
  •   Alnitak    16 年前

    在使用htaccess(即基于http的)身份验证时,没有干净的方法来实现“注销”功能。

    这是因为这样的身份验证使用HTTP错误代码“401”告诉浏览器需要凭据,此时浏览器提示用户提供详细信息。从那时起,在浏览器关闭之前,它将始终发送凭证,而无需进一步提示。

        13
  •  1
  •   Josef Sábl    15 年前

    到目前为止,我找到的最佳解决方案是 $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身份验证在浏览器中持续,他就保持注销状态。

        14
  •  1
  •   Toby Allen mercator    12 年前

    也许我错过了重点。

    我发现结束HTTP身份验证最可靠的方法是关闭浏览器和所有浏览器窗口。您可以使用javascript关闭浏览器窗口,但我认为您不能关闭所有浏览器窗口。

        15
  •  0
  •   symcbean    13 年前

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

        16
  •  0
  •   CIRCLE    9 年前

    唯一有效的方法就是 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');
    }
    
        17
  •  0
  •   johnwayne    7 年前

    这里有很多非常复杂的答案。在我的特定案例中,我找到了一个干净而简单的注销修复方法。我还没有进行边缘测试。 在我登录的页面上,我放置了一个类似以下内容的注销链接:

    <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页面。否则,您可以通过在实际登录提示之前在流程中引入一个额外的gateweeper步骤来集中注销,需要输入一个短语才能到达登录的目的地。