やりたいこと・前提
以下のような流れの、パスワード更新フォームを作るとします。
①フォームから、元パスワードと新パスワードを送信
①現パスワードの一致チェック
②新パスワードを登録
前提
公式の「シンプルな認証と認可のアプリケーション」を参考に、ログイン・ログアウトの仕組みが実装されている。
コード
フォーム(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のパスワード更新フォームに関する記事はなかなか発見できませんでした。
公式を確認しつつ、ひとつひとつ機能を組み合わせていったところ、無事に問題なく稼働するパスワード更新フォームをつくることができました。

 
  
  
  
  

コメント