basic認証で3回認証を求められます - PHPプロ!Q&A掲示板

4030

  • 0P

basic認証で3回認証を求められます

質問日時 / 2013年5月4日 16:09    回答数 / 5件

Questioner:  naka3939  このエントリーをはてなブックマークに追加 

キーワード / キーワードが設定されていません

初心者です。
basic認証のサンプルコードを書いたのですが、
ID・パスワードが合っているのに3回認証画面が出ます。
合っている場合は普通その後に認証画面が出ることは
ないはずと思うのですが、どこがおかしいのでしょうか。
ご教示お願いします。

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<?php 

$user="naka";
$pass="ok";
$realm="test";

Header("WWW-authenticate: basic realm=\"$realm\""); 
Header("HTTP/1.0 401 Unauthorized"); 

if(empty($_SERVER['PHP_AUTH_USER'])||$_SERVER['PHP_AUTH_USER']==""){ 

echo "キャンセルされました";

}else if($_SERVER['PHP_AUTH_USER']==$user && $_SERVER['PHP_AUTH_PW']==$pass){ 

echo "認証完了"; 

}else { 

Header("WWW-authenticate: basic realm=\"$realm\""); 
Header("HTTP/1.0 401 Unauthorized"); 
echo "認証に失敗しました"; 

}
  
?>


 
</body>
</html>

この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。



ツリー一覧

┗A01ockeghemいくつか問題があります。 (1)headerを必ず出力し
 ┗A01-1To_aru_Userockeghemさんのコードで完璧ですが、変更した個所につ
  ┗A01-1-1naka3939お礼と質問を書いたつもりが何故か書き込まれていませ
   ┗A01-1-1-1ockeghem返信ありがとうございます。 >ご回答頂いたコード
    ┗A01-1-1-1-1naka3939すみません。 また返信が書き込まれていませんでした

回答一覧

並び替え:

A01
answererockeghem [5月4日 20:26]

いくつか問題があります。

(1)headerを必ず出力している
 認証の成功可否に関わらず、401を返しています。これだと、永遠に認証に成功することができません。まず、IDとパスワードを確認して、認証に失敗した場合のみに401を返すべきです。

(2)headerはHTMLを返す前に
 これは、PHPのheader関数の説明にあるとおりですが、HTMLを出力する前にheader関数を呼ぶ必要があります。現状動いているように見えますが、おそらくバッファリングの関係でたまたま動いているのでしょう。

http://php.net/manual/ja/function.header.php

これを避けるためには、まず認証のロジックをすべて終えた後にHTMLを出力するようにします。

動くサンプルを書いてみましたので、参考になさって下さい。

  1. <?php
  2. define('USER''naka');
  3. define('PASS''ok');
  4. $realm="test";
  5. $user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
  6. $pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
  7. $ok_auth = false;
  8.  
  9. if($user === USER && $pass === PASS) {
  10.   $ok_auth = true;
  11. } else {
  12.   header("HTTP/1.0 401 Unauthorized");
  13.   header("WWW-authenticate: basic realm=\"$realm\"");
  14. }
  15.  
  16. ?><html>
  17. <head>
  18. <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  19. </head>
  20. <body>
  21. <?php
  22. if ($ok_auth) {
  23.   echo "認証完了";
  24. }else {
  25.   echo "認証に失敗しました";
  26. }
  27. ?>
  28. </body>
  29. </html>

この意見に回答する

ツリーへ TOPへ

A01-1
replyerTo_aru_User [5月4日 23:25]

ockeghemさんのコードで完璧ですが、変更した個所について、未説明の場所に重要事項が隠されているので、(私なりに)説明させていただきます。

1. 「empty」キーワードの使い方を間違えている

マニュアルを細部までお読みください。

issetキーワード
http://php.net/manual/ja/function.isset.php

emptyキーワード
http://php.net/manual/ja/function.empty.php

  1. <?php
  2. empty($_SERVER['PHP_AUTH_USER']) || $_SERVER['PHP_AUTH_USER']==""
は冗長で、
  1. <?php
  2. empty($_SERVER['PHP_AUTH_USER'])
で十分です。
ところがemptyは文字の '0' も空とみなしてしまうので、最も適切なのは
  1. <?php
  2. !isset($_SERVER['PHP_AUTH_USER']) || $_SERVER['PHP_AUTH_USER']===''
です。


2. 「==」「!=」演算子は特定の場合を除き、絶対に使ってはいけない

ブログにまとめました。
http://bloggdgd.blog28.fc2.com/blog-entry-275.html

PHP特有の「暗黙の型変換」を避けるために「===」「!==」を使用すべきです。

この意見に回答する

ツリーへ TOPへ

A01-1-1
replyernaka3939 [5月6日 14:10]

お礼と質問を書いたつもりが何故か書き込まれていませんでした。

あらためてありがとうございます。
ご回答頂いたコードで上手く行きましたが、一度認証した後は
再度認証せずに「認証完了」と出ます。
アクセスする度に認証画面を出すにはどうすれば良いのでしょうか。

この意見に回答する

ツリーへ TOPへ

A01-1-1-1
replyerockeghem [5月6日 22:39]

返信ありがとうございます。

>ご回答頂いたコードで上手く行きましたが、一度認証した後は
>再度認証せずに「認証完了」と出ます。

これは、BASIC認証のIDとパスワードを覚えていてリクエストの度に送信するためです。
一般にBASIC認証とはそのようなものと受け入れられています。

>アクセスする度に認証画面を出すにはどうすれば良いのでしょうか。

アクセスする度に認証画面を出すには、少しトリッキーなプログラミングが必要になると思います。通常、そのような仕様にはしないからです。
以下のサンプルでは、セッション変数に以前のログイン状態を覚えておき、以前がログイン状態であったならばいったん401ヘッダを送信して、強制的にログインプロンプトを表示させるようにしています。
テストの結果、意図通り動くようですが、不自然なプログラムであり、個人的にはお勧めできません。

  1. <?php
  2. session_start();
  3.  
  4. define('USER''naka');
  5. define('PASS''ok');
  6. $realm="test";
  7. $user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
  8. $pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
  9. if (isset($_SESSION['IS_LOGIN'])) {
  10.   $_SESSION['IS_LOGIN'] = false;
  11. }
  12.  
  13. if($_SESSION['IS_LOGIN'] && $user === USER && $pass === PASS) {
  14.   $_SESSION['IS_LOGIN'] = true;
  15. } else {
  16.   header("HTTP/1.0 401 Unauthorized");
  17.   header("WWW-authenticate: basic realm=\"$realm\"");
  18.   $_SESSION['IS_LOGIN'] = false;
  19. }
  20. ?><html>
  21. <head>
  22. <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  23. </head>
  24. <body>
  25. <?php
  26. if ($_SESSION['IS_LOGIN']) {
  27.   echo "認証完了<br>";
  28. }else {
  29.   echo "認証に失敗しました";
  30. }
  31. ?>
  32. </body>
  33. </html>

この意見に回答する

ツリーへ TOPへ

A01-1-1-1-1
replyernaka3939 [5月12日 19:10]

すみません。
また返信が書き込まれていませんでした。
ご回答ありがとうございました。
大変参考になりました。

この意見に回答する

ツリーへ TOPへ

<<質問一覧へ



Pick Up Q&A

Q
掲示板サイトを作成するときの、コメントしたユーザーのID取得方法
 このエントリーをはてなブックマークに追加 
A
2chがどのようなハッシュ形式を使っているかは知りませんが、 概ねIPアドレスをcryptやmd5などでハッシュ値にして一部分を取り出しているものだと思います。 単純にハッシュ関数を使うだけだとIPがバレてしまう...

>>続きを読む

alice4work様 shimix様 ご回答ありがとうございます。掲示板サイトを作る上で重要なトピックです。IPアドレスの解読を防ぐためにソルトを付加する点がポイントですね。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)