Laravel使ってみた (19) - Security(パスワードリマインダーとその他) -
前回で認証的な機能を作ったのはいいけど、パスワード等を忘れた場合にメールでパスワード変更URLを通知してアクセスしてもらって新しいパスワードを設定するとかっていう形式を利用する事が出来る模様
セットアップ
まずパスワードリマインダーなAPIを使うには
- DBにテーブル等を作る必要がある
- app/config/mail.phpを設定する
- app/config/auth.phpで記載されている"reminders"なビューを作る
まずはテーブルを作る
./artisan auth:reminders
./artisan migrate
だけで解決するのでそれだけでオッケーな模様。
でメールで送る際のメールサーバー等の設定もapp/config/mail.phpに行う必要がある。でこの際にとりあえず自前なメールサーバーを使わずにgmailを使ってやってみたので
<?php
return array(
"host" => "smtp.gmail.com",
"from" => array("address" => "自分のメアド", "name" => null),
"username" => "gmailのアドレス",
"password" => "パスワード"
);
的に修正する。あくまで上記で書くんじゃなくて設定項目を変更したのだけ書いてるので
んでメールで通知する際の内容をビューで書かないといけない模様なので、app/views/emails/auth/reminder.blade.phpを作る。ちなみにこれはapp/config/auth.phpのremindersで設定を変える事が可能な模様
http://laravel.localhost/password/reset?token={% raw %}{{ $token }}{% endraw %} 的な感じで、$tokenでパスワードリマインダーで使用するトークンを取得できる。ちなみにPassword::remindなAPIで要求した場合にはpassword_remindersテーブルにデータが書きこまれ、Password::resetでパスワードを変更する要件が了承?されたら書きこまれたデータはflushされる模様
ルーティング及びアクション定義
今回もめんどくさいのでapp/routes.phpにClosure型でだら書きする
<?php
/*
app/views/emails/auth/email.blade.php
<form action="/password/remind" method="post">
{% raw %}{{Form::token()}}{% endraw %}
<input type="email" name="email" />
<input type="submit" value="remind" />
</form>
*/
Route::get(
"/password/remind",
function() {
// パスワード忘れた場合にメールアドレスを指定させてメールで通知させる為にメールアドレスを入力させる為だけのフォームビュー
return View::make("emails/auth/email");
}
);
// メールアドレスを入力させてサブミットした際に起きるアクション
Route::post(
"/password/remind",
array(
"before" => "csrf",
function() {
$email = Input::get("email", null);
if (empty($email)) {
return Redirect::to("/password/remind");
}
$credentials = array("email" => $email);
// 実行後は/password/reset(自分自身)なURLへリダイレクト(GET)
return Password::remind($credentials, function($message, $user) {
Log::info($user);
// メールメッセージ等の設定はここで
$message->subject("サブジェクト");
});
}
)
);
/*
app/views/emails/auth/reset.blade.php
@if (Session::has("error"))
{% raw %}{{ trans(Session::get("reason")) }}{% endraw %}
@endif
<form action="/password/reset" method="post">
<input type="hidden" name="token" value="{% raw %}{{ $token }}{% endraw %}" />
<input type="email" name="email" value="" />
<input type="password" name="password" value="" />
<input type="password" name="password_confirmation" value="" />
<input type="submit" value="change password" />
</form>
*/
// メールで通知したパスワード変更フォームのアクション
Route::get("/password/reset", function() {
$token = Input::get("token", null);
if (empty($token)) {
App::abort(404, "ERROR");
}
return View::make("emails/auth/reset")->with("token", $token);
});
// 上記アクションからサブミットされた際にパスワードをリセットするアクション
Route::post(
"/password/reset",
function() {
$credentials = array("email" => Input::get("email"));
return Password::reset($credentials, function($user, $password) {
$user->password = Hash::make($password);
$user->save();
return Redirect::to("/");
});
}
);
っていう感じ。微妙にわかりづらい気もするんだけど
で問題が一点。メールで送られてくるのはいいけど、そのトークン自体の有効期限的なのが無いんじゃないのかって所なんですが... メールで送られてくるURLにアクセスした際にリマインダーを行なってから一定時間を過ぎてるかチェックする等をした方が良いかと思う。一応password_remindersテーブル自体にはcreated_atなカラムがあるのでそれを使う。ただ、モデルが無いので自分で作るなりな工夫は必要かと
あと書いてないけど、ドキュメントには http://laravel.com/docs/security#password-reminders-and-reset にて、UserモデルにはRemindableInterfaceを実装している必要がある模様。ただ、laravelプロジェクト作るときのデフォルトのUserモデルには実装されてるような気がするので(ry
まぁこんなもんですね。あとの問題はどうやってこの機能テストするかなんですけど
Securityなその他なドキュメント
暗号化セクションはとりあえず(ryとして、Hash::makeなんですが、これ引数にnullを指定しても返ってくる値はnullでは無い。そこら辺注意した方が良いような気がする
っていうかLaravelの内部的な所って引数をチェックしてない箇所が多々あるのでやたらとエラーを引き起こす可能性もあるので、そこら辺は十分なテストが必要なんじゃないかっては思う