やりたいこと・前提
以下のような流れの、パスワード更新フォームを作るとします。
①フォームから、元パスワードと新パスワードを送信
①現パスワードの一致チェック
②新パスワードを登録
前提
公式の「シンプルな認証と認可のアプリケーション」を参考に、ログイン・ログアウトの仕組みが実装されている。
コード
フォーム(template)
template/users/changePassword.php
<form method="post">
<input type="password" name="password">
<input type="password" name="new-password">
<input type="submit" value="送信する">
//パスワード不一致時には、以下にエラー表示する。
<p><?= $error ?></p>
</form>
シンプルに、現パスワードと新パスワードを送信するフォームです。
バックエンド(Controller)
コード全文
src/Controller/UsersController.php
namespace App\Controller;
use Cake\Auth\DefaultPasswordHasher;
・・・その他読み込み
class UsersController extends AppController
{
public function changePassword(){
$error = "";
if ($this->request->is('post')){
//ログイン済みのユーザセッション情報
$user = $this->request->getAttribute('identity');
//現パスワード
$password = $this->request->getData('password');
//新パスワード
$newPassword = $this->request->getData('new-password');
//元パスワードの一致チェック用hasher
$hasher = new DefaultPasswordHasher();
//現パスワードとログイン済ユーザのパスワードを照合する。
if ($hasher->check($password, $user->password)) {
//更新のために該当ユーザの情報をDBから再取得
$userEntity = $this->Users->find()->where(["id" => $user->id])->first();
//パスワードを更新
$userEntity->password = $newPassword;
//ユーザ情報を保存する
if($this->Users->save($userEntity)){
//ユーザ情報を更新したので、セッションを書き換える
$this->Authentication->setIdentity($userEntity);
$error = "更新に成功しました";
}else{
$error = "更新に失敗しました";
}
}else{
$error="現在のパスワードが不一致でした";
}
}
$this->set(compact('error'));
}
}
コード解説
8~13行目:Post情報、ユーザ情報を取得する
ログイン済みユーザのセッション情報、フォームから送信されたPOST情報を取得しています。
//ログイン済みのユーザセッション情報
$user = $this->request->getAttribute('identity');
//現パスワード(POST情報1)
$password = $this->request->getData('password');
//新パスワード(POST情報2)
$newPassword = $this->request->getData('new-password');
18~22行目、35~37行目:パスワードを照合する
「フォームで入力した現在のパスワード」と「ログイン済みユーザ情報」のパスワードを照合しています。
不一致であれば、その旨エラーを返します($error)。
//元パスワードの一致チェック用hasher
$hasher = new DefaultPasswordHasher();
//現パスワードと新パスワードを照合する。
if ($hasher->check($password, $user->password)) {
・・・・・
}else{
$error="現在のパスワードが不一致でした";
}
23~26行目:ログイン済みユーザのUserEntityに新パスワードをセットする。
先ほどのコードでフォームで入力した「現在のパスワードの一致」はチェックできました。
更新用にログイン済みユーザのユーザエンティティーを取得し、パスワード情報をセットします。
//更新のために該当ユーザの情報をDBから再取得
$userEntity = $this->Users->find()->where(["id" => $user->id])->first();
//パスワードを更新
$userEntity->password = $newPassword;
※パスワードのハッシュ化について
新パスワードのセット時に「パスワードをハッシュ化(暗号化)しなくてもいいの?」と思われるかもしれません。
しかし、公式の「シンプルな認証と認可のアプリケーション」を参考に、普通にログイン認証ロジックを作っていれば、Usersのパスワード更新時に自動でハッシュ化されます。
src/Model/Entity/user.php
protected function _setPassword($password)
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
}
27~34・42行目
ユーザ情報をDBに保存します。
また、ユーザ情報を更新したので、ログインユーザセッションの情報を更新します。
更新に成功したか否かをフォームに返して表示させます。
//ユーザ情報を保存する
if($this->Users->save($userEntity)){
//ユーザ情報を更新したので、セッションを書き換える
$this->Authentication->setIdentity($userEntity);
$error = "更新に成功しました";
}else{
$error = "更新に失敗しました";
}
・・・
//フォームに保存の結果を返す。成功?失敗?
$this->set(compact('error'));
まとめ・所感
ウェブサービス運用時に、パスワード更新機能の重要度はかなり高いです。
しかし、CakePHP4・Authenticationのパスワード更新フォームに関する記事はなかなか発見できませんでした。
公式を確認しつつ、ひとつひとつ機能を組み合わせていったところ、無事に問題なく稼働するパスワード更新フォームをつくることができました。
コメント