CakePHP2でBASIC認証

事情がありCakePHPBASIC認証に挑戦。ところがPHPCakePHPもあまり詳しくなく、さらにネット転がっている情報のほとんどがCakePHP1の情報で動くまで大変苦労しました。その試行錯誤の結果を記しておきます。

まず、データベースにテーブルを作成します。今回は、usersテーブルにusernameとpasswordフィールドを作成します。これが規約だそうです。もちろん別の名前をつけても問題ありませんが、後から設定が必要になります。特にこだわりがないのであれば、下記のようにすると手間が省けるでしょう。

CREATE TABLE IF NOT EXISTS users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50),
    password VARCHAR(50),
    created DATETIME DEFAULT NULL,
    modified DATETIME DEFAULT NULL
);

次にモデルの作成。

// /app/Model/User.php
<?php
App::uses('AuthComponent', 'Controller/Component');

class User extends AppModel {

 public function beforeSave($options = array()) {
     $this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
      return true;
 }
}

beforeSave()の処理は、cake2から必要になった処理のよう。今回はBASIC認証なので問題ないが、digest認証を利用する場合には、処理が異なる。公式を参考に。

AuthComponentを呼び出すために、二行目が必要だった。本家の解説になくてしばらく悩んだ。

次にAppControllerの作成。

// /app/Controller/AppController.php
<?php
class AppController extends Controller {
    var $components = array('Session', 'Auth' => array('authenticate' => array('Basic')));

    function beforeFilter(){
        $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login', 'admin' => true);
        $this->Auth->loginRedirect = array('controller' => 'applies', 'action' => 'index', 'admin' => true);
        $this->Auth->logoutRedirect = $this->webroot;
    }
}

今回はBASIC認証を利用するので、componentsに'Basic'を指定。その他の認証方式を利用するには適切に変更すること。今回は、usersテーブルでusername, passwordを利用するので問題ないが、別のフィールド名を利用している場合には、別途指定が必要。本家を参考のこと。

次にログイン処理を行うコントローラーを作成

// /app/Controller/UsersController.php
<?php
class UsersController extends AppController {
    public $name;
    public $scaffold = "admin";

    public function admin_login() { $this->login(); }
    public function admin_logout() { $this->logout(); }

    public function login() {
      if ($this->Auth->login()) {
          return $this->redirect($this->Auth->redirect());
      } else {
          $this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth');
      }
      
    }

    // ログアウト処理
    public function logout() {
      $this->Auth->logout();
    }
    
}

$scaffold = "admin"; としているのは、scaffoldを利用して、CRUD処理の作成を省くため&usersコントローラー全体を {webroot}/admin/users というアドレスにしたいため。そうしたため、 admin_login() という login() の alias を作成した。login() と logout() は、本家のコードそのままBASIC認証は logout ができないため、logout処理は必要ない気がするが、とりあえず書いておく。

最後に空ファイルでいいので、 /app/View/Users/admin_login.ctp, /app/View/Users/admin_logout.ctp を作成すること。

これで全てのコントローラーに対してログイン処理が必要になりました。ユーザーを追加して、試してみてください。このコントローラーのこのアクションだけ認証かけたくないという場合には、コントローラー毎に下記のような処理を追加してください。

    function beforeFilter(){
        $this->Auth->allow('calendar', 'list'); // action_nameを指定
    }

BASIC認証なので、ログインフォームを書かなくていいのは大変便利ですが、セキュリティは皆無に近いでしょう。セキュリティに配慮する方は、せめてdigest認証を利用しましょう。もちろんこれも万全ではないことを指摘しておきます。

参考

  1. Authentication — CakePHP Cookbook v2.x documentation
  2. Simple Authentication and Authorization Application — CakePHP Cookbook v2.x documentation