読者です 読者をやめる 読者になる 読者になる

ITの隊長のブログ

ITの隊長のブログです。いや、まだ隊長と呼べるほどには至っていないけど、日々がんばります。CakePHPとPlayFrameworkを使って仕事しています。最近はAngular2をさわりはじめたお(^ω^ = ^ω^)

まじか!?CakePHPってBasic認証できたんですね!

CakePHP PHP セキュリティ

スポンサードリンク

http://www.flickr.com/photos/73344268@N00/3553278601
photo by junyaogura


タイトルの通りに驚きました。


.htaccess でベーシック認証をかけていたら、うまくいかなくて、「CakePHPでできたらよくね?」と思い探したらありました!




p-nt.com


ありがたやーm(_ _ )m


Basic認証をかけたいControllerのbeforeFilter()に用意すればおk


フローのイメージは、「途中idとパスワードが間違っていたらエラーにする」って感じですね。

<?php
	public function beforeFilter() {
            parent::beforeFilter();
            //Basic認証 
	    $this->autoRender = false;
	    // id
            $loginId = 'hoge';
            // passwd
            $loginPassword = 'hogehoge';

           if (isset($_SERVER['PHP_AUTH_USER'])) {
              if (! ($_SERVER['PHP_AUTH_USER'] == $loginId && $_SERVER['PHP_AUTH_PW'] == $loginPassword)) {
                 $this->basicAuthError();
              }
            } else {
        	// 失敗したら途中で処理終了
                $this->basicAuthError();
            }
	    $this->autoRender = true;
	}

〜 省略 〜

	private function basicAuthError() {
            header('WWW-Authenticate: Basic realm="Please enter your ID and password"');
            header('HTTP/1.0 401 Unauthorized');
            die("Invalid id / password combination.  Please try again");
	}


自分はコンポーネントにして実装しました。


よかった。うまくいったわ

疑問が2つ


このソースだけみると疑問が2つ

  • どーして $_SERVER で、条件を判定するのか。
  • どーして $this->autRender をfalseにしなければならないのか。


せっかくなので調べてみる。

$_SERVER を調べる


ログに出力してみると、中身がこんな感じでした。

2015-05-01 11:48:40 Error: Array
(
    [REDIRECT_STATUS] => 200
    [HTTP_HOST] => localhost
    [HTTP_CONNECTION] => keep-alive
    [HTTP_CACHE_CONTROL] => max-age=0
    [HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    [HTTP_USER_AGENT] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36
    [HTTP_REFERER] => http://localhost/
    [HTTP_ACCEPT_ENCODING] => gzip, deflate, sdch
    [HTTP_ACCEPT_LANGUAGE] => ja,en-US;q=0.8,en;q=0.6
    [HTTP_COOKIE] => CAKEPHP=619pd9buil7r1mdelgluegivf5
    [PATH] => /usr/bin:/bin:/usr/sbin:/sbin
    [SERVER_SIGNATURE] => 
    [SERVER_SOFTWARE] => Apache
    [SERVER_NAME] => localhost
    [SERVER_ADDR] => ::1
    [SERVER_PORT] => 10082
    [REMOTE_ADDR] => ::1
    [DOCUMENT_ROOT] => /Users/user/cakephp
    [REQUEST_SCHEME] => http
    [CONTEXT_PREFIX] => 
    [CONTEXT_DOCUMENT_ROOT] => /Users/user/cakephp
    [SERVER_ADMIN] => you@example.com
    [SCRIPT_FILENAME] => /Users/user/cakephp/app/webroot/index.php
    [REMOTE_PORT] => 58849
    [REDIRECT_URL] => /
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.1
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [REQUEST_URI] => /
    [SCRIPT_NAME] => /app/webroot/index.php
    [PHP_SELF] => /app/webroot/index.php
    [PHP_AUTH_USER] => hoge // これがid
    [PHP_AUTH_PW] => hogehoge // これがパスワード
    [REQUEST_TIME_FLOAT] => 1430966920.197
    [REQUEST_TIME] => 1430966920
)


なるほど、サーバのグローバル変数で管理すればどこでも参照が可能になるからかな。


ということでひとつ実験。全部リフレッシュするとログインできなくなるよね。

<?php
〜 省略 〜
        $loginPassword = 'hogehoge';

        // 空っぽにする
        $_SERVER = array();
        if (isset($_SERVER['PHP_AUTH_USER'])) {
            if (! ($_SERVER['PHP_AUTH_USER'] == $loginId && $_SERVER['PHP_AUTH_PW'] == $loginPassword)) {
            	$this->basicAuthError();
            }
        } else {
〜 省略 〜


予想通り、再認証が必要になったった。

$this->autoRender を調べる


autoRender は、Viewを利用するかをしないかを決めるプロパティだ。


この辺でピンときました。


Basic認証は認証するidとパスワードを入力してもらう際、小さなポップアップみたいなブロックがでてきますが、その際にViewを使用しないようにfalseを使っていると思います。


では、実験。Basic認証前にfalseにしたautoRenderの記述を削除します。

<?php
〜 省略 〜
	public function beforeFilter() {
            parent::beforeFilter();
            //Basic認証 
	    // $this->autoRender = false; コメントアウト
〜 省略 〜


何も起こりませんでした(´・ω・)


普通に認証できましたね。なんでだろう?


とりあえず、ちょっとした疑問が無くなったので(新しい疑問は浮かびましたが)良しとします。


※この記事書いている時に見つけましたが、もう少し簡単な方法がある。今度はそれをブログに乗っけます。