HTTP認証保護フォルダーからログアウトする正しい方法は何ですか?
これを実現できる回避策はありますが、バグが発生したり、特定の状況やブラウザで機能しない可能性があるため、潜在的に危険です。それが私が正確でクリーンな解決策を探している理由です。
Miscellaneous -> Clear Private Data -> HTTP Authentication
HTTP認証保護フォルダーからログアウトする正しい方法は何ですか?
これを実現できる回避策はありますが、バグが発生したり、特定の状況やブラウザで機能しない可能性があるため、潜在的に危険です。それが私が正確でクリーンな解決策を探している理由です。
Miscellaneous -> Clear Private Data -> HTTP Authentication
回答:
ムー。正しい方法は存在せず、ブラウザ間で一貫した方法もありません。
これは、HTTP仕様(セクション15.6)に起因する問題です。
既存のHTTPクライアントとユーザーエージェントは、通常、認証情報を無期限に保持します。HTTP / 1.1。は、サーバーがクライアントにこれらのキャッシュされた資格情報を破棄するように指示する方法を提供しません。
一方、セクション10.4.2には次のように書かれています。
要求にすでに認証資格情報が含まれている場合、401応答は、それらの資格情報の認証が拒否されたことを示します。401応答に前の応答と同じチャレンジが含まれていて、ユーザーエージェントが少なくとも1回は認証を試みている場合、エンティティには関連する診断情報が含まれている可能性があるため、ユーザーには応答で指定されたエンティティを提示する必要があります(SHOULD)。
言い換えると、(@ Karstenが言うように)ログインボックスを再び表示できる可能性がありますが、ブラウザは要求を受け入れる必要はありません。この(誤った)機能にあまり依存しないでください。
Safariでうまく機能するメソッド。FirefoxとOperaでも機能しますが、警告が表示されます。
Location: http://logout@yourserver.example.com/
これは、以前のユーザー名を上書きして、新しいユーザー名でURLを開くようブラウザに指示します。
user:password@host
は非推奨です。のみを使用することhttp://logout@yourserver.example.com/
はできませんし、ほとんどの場合に機能するはずです。
簡単な答えは、http-authenticationから確実にログアウトできないことです。
長い答え:(
他のHTTP仕様と同様に)Http-authはステートレスであることを意図しています。したがって、「ログイン」または「ログアウト」することは、実際には理にかなった概念ではありません。それを確認するより良い方法は、HTTPリクエストごとに(そして、ページのロードは通常複数のリクエストであることを覚えておいてください)、「リクエストしていることを実行することを許可されていますか?」です。サーバーは、各要求を新しいものとして認識し、以前の要求とは無関係です。
ブラウザーは、最初の401でユーザーに伝えた資格情報を記憶し、その後の要求に対するユーザーの明示的な許可なしに再送信することを選択しています。これは、ユーザーが期待する「ログイン/ログアウト」モデルをユーザーに提供しようとする試みですが、これは純粋に策略です。この状態の持続をシミュレートしているのはブラウザです。Webサーバーはそれを完全に認識していません。
したがって、「ログアウト」は、http-authのコンテキストでは、ブラウザによって提供される純粋なシミュレーションであり、サーバーの権限の範囲外です。
はい、クラッジがあります。しかし、それらはRESTful性(それがあなたにとって価値がある場合)を壊し、信頼性がありません。
サイト認証にログイン/ログアウトモデルが絶対に必要な場合、最善の策は、何らかの方法(mysql、sqlite、flatfileなど)でサーバーに保存された状態の永続性を備えた追跡Cookieです。これには、たとえばPHPですべてのリクエストを評価する必要があります。
回避策
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の場合 -認証キャッシュをクリアしてどこかにリダイレクトする
他のブラウザーの場合 -「logout」ログイン名とパスワードを使用して、舞台裏で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基本認証レルムがあり、ボブがログインしているとします。ログアウトするには、2つのAJAXリクエストを作成します。
WWW-Authenticate: Basic realm="Password protected"
この時点で、ブラウザはボブの資格情報を忘れていました。
この問題に対する私の解決策は次のとおりです。あなたは機能を見つけることができ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;
}
通常、ブラウザーがユーザーに資格情報を要求し、それらを特定のWebサイトに提供すると、それ以上のプロンプトは表示されずに続行されます。クライアント側でCookieをクリアするさまざまな方法とは異なり、ブラウザーに提供された認証資格情報を忘れるように要求する同様の方法は知りません。
Trac-デフォルトでは-HTTP認証も使用します。ログアウトは機能せず、修正できません:
- これはHTTP認証スキーム自体の問題であり、Tracで適切に修正するためにできることは何もありません。
- 現在、すべての主要なブラウザーで動作する回避策(JavaScriptまたはその他)はありません。
差出人: http : //trac.edgewall.org/ticket/791#comment : 103
質問に対する有効な回答はないようです。その問題は7年前に報告されており、完全に理にかなっています。HTTPはステートレスです。リクエストは認証資格情報で行われるかどうか。しかし、それはサーバーが要求を受け取るのではなく、クライアントが要求を送信することの問題です。サーバーは、リクエストURIが承認を必要とするかどうかのみを伝えることができます。
.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は他のブラウザーのように認証をクリアしません;)
インストールしたブラウザでテストしましたが、いったん閉じると、各ブラウザは常に再入時に再認証を必要とするようです。
WWW-Authenticate
問題が発生し、自動的にログアウトされました。
WWW-Authenticate
と、別のブラウザー(Firefox)が資格情報を記憶し、次のリクエストでそれらを送信して、自動的に再ログインするようになります。ああ!
これは探していた解決策ではないかもしれませんが、私はこのように解決しました。ログアウトプロセス用の2つのスクリプトがあります。
logout.php
<?php
header("Location: http://.@domain.com/log.php");
?>
log.php
<?php
header("location: https://google.com");
?>
このようにして警告が表示されず、セッションが終了します
これまでに見つけた最善の解決策は$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認証が持続している限り、ログアウトしたままになります。
多分私はポイントを逃しています。
HTTP認証を終了するために私が見つけた最も信頼できる方法は、ブラウザーとすべてのブラウザーウィンドウを閉じることです。JavaScriptを使用してブラウザウィンドウを閉じることはできますが、すべてのブラウザウィンドウを閉じることはできないと思います。
ここにはたくさんの素晴らしい-複雑な-答えがあります。私の特定のケースでは、ログアウトのためのクリーンでシンプルな修正を見つけました。まだ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ページが必要になることを認めます。それ以外の場合は、実際のログインプロンプトの前にプロセスに追加のゲートキーパーステップを導入することでログアウトを集中化でき、ログインの宛先に到達するにはフレーズの入力が必要になります。