ZendFrameworkで構築したサイトの一部にbasic認証をかけたいけど、どうしたらできるか知ってる?と聞かれたのでやってみました。
考えたことなかったですが、.htaccess使うとindex.phpと同じ階層に置くことになって、サイト全体にしかかけれないのかもしれません。試してはないので推測です。
やりたかった内容は、特定のURLにbasic認証をかけて、認証NGな場合は他の画面を表示し、認証OKな場合は、そのまま指定されたURLの画面を表示するというものです。
サンプルソースは、以下になります。
今回は、controller内に全部書きました。
public function testAction()
{
$config = array(
'accept_schemes' => 'basic', // basic認証指定
'realm' => 'aaaaa', // realm(passwd.txtの内容と一致させる必要あり)
'digest_domains' => '/login/', // このURL以下には全てbasic認証要
'nonce_timeout' => 3600
);
$resolver = new Zend_Auth_Adapter_Http_Resolver_File();
$resolver->setFile('passwd.txt'); // index.phpがある階層と同じところに置いてます。
$adapter = new Zend_Auth_Adapter_Http($config);
$adapter->setBasicResolver($resolver)
->setRequest($this->getRequest())
->setResponse($this->getResponse());
$result = $adapter->authenticate();
if (!$result->isValid()) {
// 認証エラーの場合
return $this->_forward('test1');
}
// 認証OK
}
passwd.txtの中身はこちら
test:aaaaa:hogehoge
左から、アカウント、realm、パスワードです。パスワードは生パスワードでOKです。
realmは、はプログラム内で指定したものと一致する必要があります。
アカウントとrealmが一対となっていて、それに対してパスワードが存在するイメージです。
basic認証の画面は、authenticate()の部分で生成され、Zend_Controller_Response_Httpに設定されています。
authenticate()の部分で実行されるということは、認証画面が表示される際は、必ず “認証エラー” のルートを通ることになります。
なので、このルートを単なるエラールートと捉えない方がいいです。例えば、Exceptionをthrowしたりしたら、必ずthrowされます。
あと、はまった点が1つありました。”認証エラー”のルートに $this->_redirect()を利用すると、期待する動きはしません。
basic認証画面の出力より、リダイレクト処理が優先されてしまい、常にリダイレクトされることになります。
そのため、上記サンプルでは $this->_forward()を利用しています。これなら、認証画面にてキャンセルを押した場合にforward先の画面が出力されます。
Zendのソースを見つつ、認証画面にてキャンセルを押された場合を検出しようとしたんですが、判別の方法がわかりませんでした。
認証画面をキャンセルした際に、サーバ側にリクエストがきてないようだったので、サーバ側で判別するのは無理と判断しました。
今回は、Responseにbasic認証の情報と、forwardの情報を両方設定し、basic認証がキャンセルされたら、forwardが実行される形になりました。
あ、realmが必須だったからだと思います。自前で作成した理由。
>nakajijapan
なるほど。realmを空行にしようとしたけど、エラーになりますね。
認証画面にメッセージとして出てくるから、必要ないときは確かに邪魔かも。