携帯の固有IDのみで認証

Authコンポーネントによる認証は、通常はusersのusernameとpasswordの照合で行うので、この2項目の登録が必須*1ですが、

携帯の固有IDの登録のみで認証を通す方法もありました。

(追記:1/20 22:32 id:ockeghemさんからのご指摘を受けて、IPチェックの必要性について追記しました。)


まず、前提として、usersが以下のような内容になっているとします。

mysql> SELECT id, name, username, password, mobile_id FROM users WHERE id=2\G
*************************** 1. row ***************************
       id: 2
     name: Cake
 username:
 password:
mobile_id: eecca936b0ef58ba3ad38ba924b89a69e0a151b4
1 row in set (0.00 sec)

このユーザは、username/passwordの登録がありません*2
代わりにmobile_idに、暗号化した固有ID*3が保存されています。


このユーザを認証するためのメソッドは、こんな感じになります。

function mobile_login() {

	$auth = $this->AuthorizedByMobileID();

	if ($auth) {
		$this->redirect('/m/');
	} else {
		$this->errorMsg = 'この携帯は登録されていません。';
	}
	$this->disp_mobile_error();
}


/* 端末IDで認証発行 */
function AuthorizedByMobileID() 
{
	$this->set_mobile_uid();

	$this->User->primaryKey = 'mobile_id';
	return $this->Auth->login($this->Auth->password($this->agent->getUID()));
}
要はこの2行。
$this->User->primaryKey = 'mobile_id';

UserモデルのprimaryKey設定を、mobile_idに書き換え、

return 
$this->Auth->login($this->Auth->password($this->agent->getUID()));

$this->Auth->login()に、

  1. 暗号化した($this->Auth->password())
  2. 固有ID($this->agent->getUID())

の文字列を渡します。


usersに固有IDが登録されていればtrue, されてなければfalseを返すので、それに応じてアクションソッド mobile_login()で、リダイレクト処理を実行。

$this->Auth->login($data)処理について

$this->Auth->login($data)の実行で認証発行が可能なことは、CookBookにも記載されています。
http://book.cakephp.org/ja/view/388/login


通常は、$dataに、$this->data由来の

$data = array(
	'Users' => array(
		'username' => 'admin',
		'password' => 'b9fec6e1801150203530ac4f8fa385218d6ee6ff',
	)
);

のような配列を渡すのが一般的ですが、

$dataは、array型の他、オブジェクトや文字列を渡すことも可能です。


$dataにオブジェクトを渡した場合は、そのオブジェクトから$data->read()で、上記のようなユーザ情報配列を取り出し、usersにusernameとpasswordが合致するユーザがいれば認証OK。


$dataに文字列を渡した場合は、$Auth->primaryKeyで設定されたusersのカラム(デフォルトでid)が$dataと一致するユーザで認証OK、という仕組みになっています。


今回は、この「文字列渡し」を使用しました。

[参考]cale/libs/controller/components/auth.php 823行目 indentify()の一部
} elseif (!empty($user) && is_string($user)) {
	$model =& $this->getModel();
	$data = $model->find(array_merge(array($model->escapeField() => $user), $conditions));
	if (empty($data) || empty($data[$this->userModel])) {
		return null;
	}
}
固有IDの取得について

なお、$this->set_mobile_uid()は、PEARのNet_UserAgent_Mobileを使用するメソッド。
$this->agentに端末情報をセットして、固有ID取得のエラー処理(含むエラー画面遷移)を行っていますが、ここでは詳細省略します。
  Net_UserAgent_Mobileの使い方参考
CakePHP 携帯専用サイトを作成する | Sun Limited Mt.
CakePHP その20 〜1.2RC2でPC&携帯対応サイトを考えた 〜:sandmanの旅行の写真”とか”:So-netブログ

他、認証引継ぎなど

上記ソースでは省略していますが、携帯用にセッション引継の改修を別途入れています。

参考
http://d.hatena.ne.jp/hetima/20070201/1170313526
http://www.happytrap.jp/blogs/2009/03/24/797/
CakePHPで ?guid=ONを常にURLに入れる - 趣味の延長線 ←手前味噌 ^^;

(追記)運用上の注意

(ブックマークにて、id:ockeghemさんからのご指摘を受けて追記しました。ありがとうございました。)

以上、固有IDのみで認証を行う方法について記載しましたが、
実際に公開運用する際には、必ず「携帯電話からのアクセスであること」をチェックして、異なる場合はエラーで停止させる機能が別途必要になります。


理由については、以下のサイトで説明されていますが、
要約すると理由は、「固有IDは、ツールなどを使えば偽装できるから」です。
固有ID情報が流出した場合、携帯電話以外からのアクセスを許可していると、悪意の第三者にハッキングされる恐れがあります。
第2回 携帯キャリアと端末を判別する:【PHPで作る】初めての携帯サイト構築|gihyo.jp … 技術評論社


具体的には、「アクセス元のIPをチェックして、各携帯電話会社のサーバ(ゲートウェイ)のIPと照合、合致しなければエラー」という処理となります。


この先、また少し長くなるので、別記します。

*1:$Auth->fieldsの設定で、username => mailadressのような項目名変更は可能ですが、2項目、うち1つは暗号化した認証情報が必要

*2:どうしてこうなった、は省略

*3:iModeID、EZwebIDなど 端末固有ID/契約固有IDなどの種類は今回問わず