PHP ile HTTP kimlik doğrulaması çıkış

14 Cevap php

HTTP kimlik korumalı klasörün oturumu correct yolu nedir?

Orada bu elde edebilirsiniz geçici çözümler vardır, ama onlar adamcağız olabilir veya bazı durumlar / tarayıcılarda çalışmıyor çünkü potansiyel olarak tehlikelidir. Ben doğru ve temiz çözüm arıyorum nedeni budur.

14 Cevap

Mu. No correct way exists, bile tarayıcılar arasında tutarlı bir.

Bu gelen bir sorundur HTTP specification (bölüm 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.

Öte yandan, kesit 10.4.2 der:

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.

Diğer bir deyişle, you may be able to show the login box again (der {[) (1]} gibi), but the browser doesn't have to honor your request - yani bu (yanlış) bağlı olmayan çok fazla bulunmaktadır.

Safari'de güzel çalışıyor yöntem. Ayrıca Firefox ve Opera çalışır, ancak bir uyarı ile.

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

Bu, daha önceki yazılmasının, yeni adı ile URL açmak için tarayıcı söyler.

Cevap basit, güvenilir http-kimlik üzerinden oturum edemiyor olmasıdır.

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.

Tarayıcıları ilk 401 üzerinde onlara kimlik hatırlamak için seçilen ve daha sonraki istekleri kullanıcının açık izni olmadan onları yeniden gönderdin. Bu kullanıcıya bekledikleri "in / giriş çıkış yapmış" modeli vererek bir girişim olduğunu, ama bu tamamen bir kludge bulunuyor. Bu browser bu devletin bu sebat taklit ediyor bulunuyor. Web sunucusu bunu tamamen habersiz olduğunu.

Yani http-auth bağlamında, tarayıcı tarafından sağlanan tamamen bir simülasyon olduğunu "çıkıyor", ve böylece sunucunun yetkisi dışında.

Evet kludges vardır. Ama onlar sığınakta-lik kırmak (ki size değer ise) ve onlar güvenilmez.

Kesinlikle sitenizin kimlik doğrulaması için bir logged-in/logged-out modeli gerektiriyorsa, en iyi bahis bir biçimde (mysql, sqlite, flatfile, vb) sunucuda depolanan devletin kalıcılığı ile, bir izleme çerez. Bu, tüm istekleri PHP ile, örneğin, değerlendirilmek üzere gerektirir.

Workaround (! Değil temiz, güzel (hatta çalışan yorumlara bakınız) çözelti):

Onun kimlik bilgilerini bir kez devre dışı bırakın.

Siz (Oturumunuzu değilse) uygun başlıklarını göndererek PHP için HTTP kimlik doğrulama mantığını taşıyabilirsiniz:

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

Ve ile giriş ayrıştırma:

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

Yani onun kimlik bilgilerini bir kez devre dışı Önemsiz olmalıdır.

Workaround

Sen JavaScript kullanarak bunu yapabilirsiniz:

<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>

Ne yukarıda yapmış olduğunu:

  • for IE - Sadece açık kimlik doğrulama önbellek ve bir yere yönlendirmek

  • for other browsers - 'Çıkış' adı ve şifre ile perde arkasında bir XMLHttpRequest gönderebilirsiniz. Biz (yani HTTP kimlik doğrulaması gerektiren olmamalı) bu talebe 200 OK dönecektir bazı yoluna göndermek gerekiyor.

Çıkıyor sonra yönlendirmek ve 200 OK dönecektir sitenizdeki bazı yolu ile '/path/that/will/return/200/OK' olarak değiştirin bazı yolu ile '/where/to/redirect' olarak değiştirin.

Probleme olan çözüm aşağıdaki gibidir. Sen fonksiyonu bulabilirsiniz http_digest_parse, $realm ve $users Bu sayfanın ikinci örnekte: 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;
}

Bir tarayıcı kimlik için kullanıcı sordu ve belirli bir web sitesine tedarik kez Tipik olarak, daha da sormadan bunu yapmaya devam edecektir. Eğer istemci tarafında çerezleri temizleyebilirsiniz çeşitli şekillerde aksine, ben onun verilen kimlik doğrulama bilgilerini unutmak için tarayıcı sormak için benzer bir yol bilmiyorum.

Logout from HTTP Basic Auth in two steps

Diyelim ki "korumalı Şifre" adında bir HTTP Basic Auth bölge var ve Bob ben 2 AJAX isteklerini yapmak Çıkmak için oturum açmış diyelim:

  1. Erişim script / logout_step1. Bu. Htusers rastgele bir geçici kullanıcı ekler ve oturum açma ve şifre ile yanıt verir.
  2. Erişim script / logout_step2 authenticated with the temporary user’s login and password. Komut geçici kullanıcıyı siler ve cevabına bu başlık ekler: WWW-Authenticate: Basic realm="Password protected"

Bu noktada tarayıcı Bob'un kimlik unuttum.

Trac - varsayılan - yanı sıra HTTP kimlik doğrulaması kullanır. Logout çalışmıyor ve sabit olamaz:

  • Bu HTTP kimlik doğrulama şeması kendisi ile ilgili bir sorun olduğunu ve düzgün düzeltmek için Trac yapabileceğiniz hiçbir şey yok.
  • Tüm büyük tarayıcıları ile çalışır geçici bir çözüm yok (JavaScript veya başka) bulunmamaktadır.

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

Sorusuna hiçbir çalışma cevabı olduğunu, bu konu yedi yıl önce bildirilmiştir gibi görünüyor ve mükemmel mantıklı: HTTP vatansız olduğunu. Ya bir istek doğrulama kimlik bilgileri veya ile yapılır. Ama bu istemci sunucu almayan, isteği gönderme meselesi. Bir istek URI yetkilendirme ihtiyacı olmadığını sunucusu yalnızca söyleyebiliriz.

AFAIK, htaccess (yani HTTP tabanlı) kimlik doğrulaması kullanırken bir "çıkış" fonksiyonu uygulamak için temiz bir yolu yoktur.

Bu tür kimlik doğrulama bilgileri tarayıcı ayrıntılar için kullanıcıya sorar hangi noktada, gerekli tarayıcı anlatmak için HTTP hata kodu '401 'kullanır olmasıdır. Tarayıcı kapatılana kadar o andan itibaren, her zaman daha sormadan kimlik bilgilerini gönderir.

Ben buldum iyi çözüm şimdiye kadar (bu $isLoggedIn http auth için sözde değişken pseudo-code çeşit) olduğunu:

"Logout" anda sadece kullanıcı aslında dışarı oturum diyerek oturuma bazı bilgi depolamak.

function logout()
{
  //$isLoggedIn = false; //This does not work (point of this question)
  $_SESSION['logout'] = true;
}

Ben kimlik kontrol yerinde ben durumu genişletin:

function isLoggedIn()
{
  return $isLoggedIn && !$_SESSION['logout'];
}

Kullanıcı sürece o açık ve http kimlik tarayıcıda devam ettiği sürece tarayıcı tutar olarak kaydedilir kalması için Oturum biraz http kimlik doğrulama durumuna bağlıdır.

Ben sıfırlamak için gerekli htaccess yetkilendirme yüzden bu kullanılır.:

<?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

Rakam gidin.

Çözüm bir dizi bu sayfada bulunan ve hatta altındaki notlar: Lynx, diğer tarayıcılar gibi auth silmez ;)

Ben yüklü tarayıcılarda bunu test ve sürekli iniş üzerinde reauth gerektirir gibi bir kez kapalı, her tarayıcı görünüyor.

Diğerleri onun imkansız temel http kimlik doğrulaması Logouta söyleyerek doğru olsa hangi behave benzer kimlik doğrulaması uygulamak için yolu vardır. Açık bir appeoach kullanmaktır auth_memcookie. Eğer gerçekten Temel HTTP kimlik doğrulaması uygulamak istiyorsanız bu kullanarak (yani bir HTTP form daha trather oturum açmak için tarayıcı diyaloglar kullanın) -. Sadece tayininde te kullanıcı sonra geldikleri yere geri yönlendirir bir PHP komut dosyası içeren htaccess korumalı dizin için kimlik doğrulamayı memcache oturumu createing.

Belki noktayı kaçırıyorum.

HTTP kimlik doğrulaması sona bulduğum en güvenilir yolu, tarayıcı ve tüm tarayıcı pencerelerini kapatmak için olduğunu. Sen JavaScript kullanarak bir tarayıcı penceresini kapatabilir ama ben tüm tarayıcı pencerelerini kapatın sanmıyorum.