AuthComponentの認証に簡単に自動ログイン機能を追加するコンポーネント

あっという間に年末です。
飲み会が多すぎて体力的にヘタってきたsanojimaruです。

今日は、CakePHPのAuthComponentを使った認証システムに、簡単に自動ログイン機能が追加できるコンポーネント「AutoLoginComponent」を書いてみました。
今回のコンセプトは「極力変更を避ける」です。

まず、ユーザー情報を格納するテーブルに、カラムを1行追加します。

ALTER TABLE users ADD COLUMN passport VARCHAR(255) default null;

ここでは、AuthComponentのデフォルトである、usersテーブルにpassportというカラムを追加しています。
テーブル名やカラム名はAuthComponentの設定を読み込んで使用しますので、各々の環境に合わせてください。

次に、AuthComponentを読み込んでいるControllerの$componentsにAutoLoginComponentを追加します。

<?php
class AppController extends Controller {
	var $components = array('Auth', 'AutoLogin');
}
?>

次に、ログイン処理とログアウト処理を実行するアクションに処理を追加します。
デフォルトは、UsersController::login(),UsersController::logout()です。

<?php
	/**
	 * ログイン処理
	 */
	function login() {
		//ログイン判定
		if($this->Auth->user()) {
			//ログインに成功した場合、自動ログインを有功にする
			$this->AutoLogin->enable();

			$this->redirect($this->Auth->redirect());
		}
	}

	/**
	 * ログアウト処理
	 */
	function logout() {
		$this->AutoLogin->disable();
		$this->redirect($this->Auth->logout());
	}
?>

最後に、app/controllers/componentsに以下のファイルを設置します。

<?php
/**
 * AuthComponentに自動ログイン機能を付加するコンポーネント.
 * 
 * @author sanojimaru
 *
 */
class AutoLoginComponent extends Object {
	/**
	 * 使用するコンポーネント
	 * @var array
	 */
	var $components = array('Cookie');
	
	/**
	 * 呼び出し元コントローラーインスタンスの参照
	 * @var Object AppController
	 */
	var $controller;
	
	/**
	 * AuthComponentが認証に使用するモデルインスタンスの参照
	 * @var Object AppModel
	 */
	var $userModel;
		
	/**
	 * 自動ログインの有効期限.
	 * strtotime()関数でtime型に変換できる文字列.
	 * デフォルトは2週間('2weeks').
	 * @var string
	 */
	var $expire;
	
	/**
	 * userModelに対応するテーブルの、自動ログイン情報を保存するフィールド名.
	 * cookieに保存する際のキーにも使用する.	 
	 * デフォルトは'passport'
	 * @var string
	 */
	var $field;
	
	/**
	 * 呼び出し元コントローラーのbeforeFilter以前に実行される.
	 * 
	 * @param $controller 呼び出し元コントローラーインスタンス
	 */
	function initialize(&$controller) {
		//自動ログインの有効期限、2週間
		$this->expire = '2weeks';
		
		//自動ログインに使用するuserModelテーブルのフィールド名
		$this->field = 'passport';
	}
	
	/**
	 * コンストラクタ
	 * @param $controller 呼び出し元コントローラーインスタンス
	 */
	function startup(&$controller) {
		//コントローラーを取得
		$this->controller = & $controller;
		//AuthComponentから認証に使うモデルを取得
		$this->userModel = & $controller->{$controller->Auth->userModel};
		//AuthComponentの自動リダイレクト設定を切る
		$controller->Auth->autoRedirect = false;
		
		//ログイン処理
		$this->login();
	}
	
	/**
	 * 自動ログインを実行する.
	 */
	function login() {
		//ログイン済みなら終了
		if($this->controller->Auth->user()) {
			return;
		}
		
		//cookieから自動ログインキーを取得
		$passport = $this->Cookie->read($this->field);
		
		//自動ログインキーが存在する場合
		if($passport) {
			$passport = $passport[$this->field];
			
			//自動ログインキーからユーザー情報を取得
			$user = $this->userModel->find('first', array(
				'conditions' => array($this->userModel->name.'.'.$this->field => $passport)
			));

			//取得したユーザー情報でログイン
			if($this->controller->Auth->login($user[$this->userModel->name])) {
				//自動ログインキーを上書き
				$this->enable();
			}
		}
	}
	
	/**
	 * 自動ログインを使用不能にする
	 */
	function disable() {
		$this->Cookie->del($this->field);
		
		$this->userModel->id = $this->controller->Auth->user('id');
		$this->userModel->saveField($this->field, null);
	}

	/**
	 * 自動ログインを使用可能にする
	 */
	function enable() {
		$new_passport = String::uuid();

		$this->userModel->id = $this->controller->Auth->user('id');
		$this->userModel->saveField($this->field, $new_passport);
		
		$this->Cookie->write($this->field, array($this->field => $new_passport), true, '+'.$this->expire);
	}
}
?>

以上で追加作業は完了です。

なお、AutoLoginComponentの独自設定は以下の2つのみです。
・自動ログインの有効期限
・自動ログインキーを保存するカラム名

上記の例の通りに設定すれば特に指定は必要ありませんが、独自に設定する場合はAutoLoginComponentを読み込んでいるコントローラー(例だとAppController)のbeforeFilter()で設定してください。

<?php
class AppController extends Controller {

	var $components = array('Auth', 'AutoLogin');

	function beforeFilter() {
		parent::beforeFilter();
		
		/** AuthComponentの設定ここから */
		$this->Auth->userModel = 'Trader';
		/** AuthComponentの設定ここまで */
		
		/** AutoLoginComponentの設定 */
		//自動ログイン有効期限
		//strtotime()で変換可能な文字列
		$this->AutoLogin->expire = '1week';

		//ユーザー情報を持つテーブルの自動ログインキーのフィールド名
		$this->AutoLogin->field = 'autologin';
		/** ここまで */
	}
}
?>

以下については、AuthComponentの設定を読み込むので、通常であれば設定不要です。
・ユーザー情報を保持するモデル

今回は、極力簡単に追加できることが目的だったので、自動ログインできるのは1ヶ所(1端末)のみです。

ツッコミやアドバイスなど、どしどしコメントください。
よろしくお願いします。