最近、破滅派関連のhamazon.comというサイトを作っている。ベースはWordpressで、なんとかECサイトっぽくしようとがんばっている。カート部分はSSL通信を利用しようと思ったんだけれど、共有サーバなので、SSLのドメインが変わってしまう。こんな感じ。
- 通常ドメイン http://hamazon.hametuha.com
- SSL利用時 https://server.jp/hametuha/hamazon
.htaccessで回避する方法(英語)もあるらしいけど、Wordpressのユーザ認証を別アプリにかませることができれば自分の今後に役立ちそうだなと思ったので、がんばってやってみた。
で、北京オリンピックの柔道を見ながら(泉浩が負けた! ショック!)小三時間、Google先生に聞いても全然わからなかったが、なんとか解決した。以下の設定で解決編と行きます。
パスワード認証 powered by WordPress解決編
基本設定
- ホームページ http://example.com
- SSLログイン https://sslpath.jp/login
- 買い物カゴ https://sslpath.jp/login/cart
- Wodpressバージョン 2.5.1
ちなみに、WordpressはCookieを利用してユーザを判別するので、もしログインした状態でSSLログイン画面に映るときは、GETメソッドでemailアドレスを渡す。これは以下の関数で呼び出しておく。
<?php global $userdata; get_currentuserinfo(); $userEmail = $userdata->user_email ?>
で、GETメソッドで渡したら、ログイン画面のinputタグに叩き込む。まあ、これはなくても大丈夫です。
WordPressのパスワード生成の基本的な仕組み
phpMyAdminなんかでWordpressのDBを覗き込むと、wp_usersテーブルにパスワードが書かれている。よくパスワードを忘れたときなんかにここを直接書き換えたりしてしまいがちなんだけれど、絶対うまくいかない。
なぜなら、セキュリティ上md5という方法でハッシュ化(暗号化ではなく、不可逆的な方法で乱数化すること)されているからである。やってしまいがちな方は〔参考:WordPressでパスワード忘れの時はMD5化して突っ込む〕をどうぞ。
以上の情報を知り、「だったらphpの組み込み関数md5()で同じくハッシュ化して検証すりゃいいじゃん」ということで、以下の方法を試したが、無理だった。
<?php $enterPass; //ユーザーがinputタグに入力したパスワード $dbPass; //データベースに入ってるパスワード if($dbPass == md5($enterPass)): echo "認証OK"; endif; ?>
というのは、Wordpress2.5+で用いられているハッシュ化アルゴリズムは、単なるmd5じゃなくて、phpassというフレームワークを利用しているからだそうな。サイトを見ると、英語でずらーっと書いてあり、面倒だなと感じてこちらを解読するのは断念。
解決編
で、結局のところ、もともとWordpressに備わっているパスワード生成関数を解読すればハッシュ化のアルゴリズムが解読できるのでは、と気付いた。
で、どこでやっているのかしらと調べると、wp-includes/pluggabel.phpらしい。そういえば、何度かパスワード周りでWordpressをクラッシュしたときは、このファイルでFatal errorが起きていた。
さっそくwp-includes/pluggabel.phpの中を見てみると、1134行目にwp_check_password($password, $hash, $user_id = ”) {}というそのものズバリの関数が定義されているじゃありませんか!
引数の意味はそれぞれ以下の通りです。wp_check_passwordの戻り値はboolean型(true or false)です。
- $password:合っているかどうか確かめたいパスワード。この場合は、ユーザがテキストボックスに入力したパスワード。
- $hash:データベースに格納されているパスワード。僕が作ったログインフォームでは、メールアドレスを頼りにwp_usersから引っこ抜きました。PDOかPEAR::MDB2あたりを使えば簡単です。
- $user_id:$hashと同じ方法でデータベースから引っこ抜く。
一点だけ注意しなくてはいけないのは、wp-includes/pluggabel.phpではABSPATHという定数を利用しており、これでwp-includes/class-phpass.phpをインクルードしています。なので、こんな感じで書けばOK
<?php //ABSPATHを定義 define("ABSPATH","/Wordpressのホームディレクトリまでのパス/"); //ABSPATHを華麗に再利用しつつ、pluggable.phpをインクルード include(ABSPATH."wp-includes/pluggable.php"); //入力されたパスワード、DB内のパスワード、ユーザIDを取得 $enterPass; $dbPass; $dbID; //wp_check_passwordで検証 if(wp_check_password(<em>$enterPass</em>,<em>$dbPass</em>,<em>$dbId</em>)): //認証成功時の処理 else: //認証失敗時の処理 endif; ?>
いやあ、これでなんとかなりそうですね。今夜も気持ちよく眠れそうです。柔道女子70kg級の上野雅恵も金メダルだったし、よかったよかった。