こんにちは、エンジニアの@soyanaです。
CakePHP では、バージョン 2.4 から passwordhasher という仕組みが導入され、認証オブジェクトがパスワードハッシュの生成とチェックを行うために、新たなパスワードハッシュ化オブジェクトを使うようになりました。 これにより、デフォルトで用意されているパスワードハッシュ化アルゴリズム以外のものを使いたい場合に、容易に差し替えることができるようになっています。
既に WordPress など他のシステムにより生成されたユーザーテーブルをそのまま扱って Cakephp で開発し直すことがあるかもしれません。
そういった場合に、この passwordHasher という仕組みを使うと認証を少ないコードで容易にカスタマイズすることができます。
ここでは、WordPress からの移行を例にとって、その方法をご紹介していきます。
やることは次の3つです。
- phpass を Vendor ディレクトリに置く
- カスタムした PasswordHasher クラスの作成
$components
に passwordHasher を指定
ユーザーモデル
まず、前提として、WordPress のユーザーデータが保存されているテーブル wp_users
を扱うモデルが定義済みだとします。
<?php // app/Model/User.php class User extends AppModel { public $name = 'User'; public $useTable = 'wp_users'; public $primaryKey = 'ID'; }
phpass を Vendor ディレクトリに設置
WordPress では、パスワードのハッシュ化に phpass というフレームワークを用いています。
WordPress のソースコードにも phpass クラスは同梱されてはいるのですが、
phpass 公式サイトで公開されているソースコードをダウンロードすることにします。
Portable PHP password hashing ("password encryption") framework からダウンロードした phpass-{version}.tar.gz を展開すると、PasswordHash.php
が含まれています。フレームワークというほど大げさなものではなく、実体は250行の1つのクラスファイルです。これを app/Vendor/
ディレクトリ以下に配置します。app/Vender/phpass/passwordhasher.php
として置かれたとします。
カスタムした PasswordHasher クラスの作成
CakePHP デフォルトのハッシュ化クラス Simple
は sha1, sha256、md5 ハッシュを使えます.
また、Blowfish password hasher も組み込みで用意されていますが、phpass は選べません。
phpass パスワードハッシュを使えるように、PasswordHasher クラスを Component として作成します。このクラスには、hash メソッドと check メソッドを実装します。 といっても、phpass に ハッシュ化する HashPassword メソッドと CheckPassword メソッドが用意されており、 対応するメソッドを呼ぶだけです
<?php // app/Controller/Component/Auth/PhpassPasswordHasher.php App::uses('AbstractPasswordHasher', 'Controller/Component/Auth'); App::import('Vendor', 'phpass/PasswordHash'); /** * Phpass password hashing class. */ class PhpassPasswordHasher extends AbstractPasswordHasher { /** * Generates password hash. * * @uses PasswordHash::HashPassword * @param string $password Plain text password to hash. * @return string Password hash * @link http://www.openwall.com/phpass/ */ public function hash($password) { $hasher = new PasswordHash(8, true); return $hasher->HashPassword($password); } /** * Check hash. Generate hash for user provided password and check against existing hash. * * @uses PasswordHash::CheckPassword * @param string $password Plain text password to hash. * @param string $hashedPassword Existing hashed password. * @return boolean True if hashes match else false. */ public function check($password, $hashedPassword) { $hasher = new PasswordHash(8, true); return $hasher->CheckPassword($password, $hashedPassword); } }
$components に passwordHasher を指定
認証の際のパスワードハッシュ化に phpass を使うよう、AppController.php にて上記で作成した passwordHasher を指定します
<?php // app/Controller/AppController.php class AppController extends Controller { public $components = array( 'Auth' => array( 'authenticate' => array( 'Form' => array( 'userModel' => 'WpUser', 'fields' => array('username' => 'user_login', 'password' => 'user_pass' ), 'passwordHasher' => 'Phpass' ) ), );
パスワード保存時のハッシュ化
新規ユーザ作成時やパスワードの変更する場合など、ユーザのパスワードをユーザーテーブルに保存する際に、phpass によりパスワードをハッシュ化するよう、User モデルの beforeSave メソッドに処理を書きます。
<?php // app/Model/User.php App::uses('PhpassPasswordHasher', 'Controller/Component/Auth'); class User extends AppModel { public function beforeSave($options = array()) { if (!$this->id) { $passwordHasher = new PhpassPasswordHasher(); $this->data['User']['user_pass'] = $passwordHasher->hash($this->data['User']['user_pass']); } return true; } }
これでできました。簡単ですね。
WordPress で構築されたシステムに登録されたユーザデータをそのまま維持して、CakePHP で作り変えることになっても、全ユーザのパスワードがリセットしなければなんてことにはならず、スムーズに移行することができますね。 また、他のハッシュアルゴリズムによりパスワードが保存されているユーザテーブルを扱う場合にも、同様の方法を適用することができるでしょう。