ポンコツエンジニアのごじゃっぺ開発日記。

いろいろポンコツだけど、気にするな。エンジニアの日々の開発などの記録を残していきます。 自動で収入を得られるサービスやシステムを作ることが目標!!

【Laravel 8.x】パスワードのバリデーションを使いこなそう。

Laravel 8.xからパスワード入力に対するバリデーションが使いやすくなりました。

そこで、実際に使ってみながら試してみました。

パスワードの入力ルールを作成する

Laravel 8.xのパスワードのバリでションについては、日本語のドキュメントではこちらになります。

readouble.com

Illuminate\Validation\Rules\Passwordに対してメソッドがいくつか用意されているので、それを利用しつつPHPのメソッドチェーンの形で定義をしていきます。ただし、Passwordクラスの中身を読むと、staticなメソッドはmin()のみっぽいので、Password::min(size)から始めないといけなそうです。(後に説明するdefaultを除いて)

メソッド 内容
min(size) 最低$size文字以上必要
mixedCase() 大文字と小文字が1文字ずつ必要
letters() 最低1文字の文字が必要
number() 最低1文字の数字が必要
symbols() 最低1文字の記号が必要
uncompromised($threshold = 0) パスワードのデータ漏えいがないことを確認

メソッドチェーンの利用方法として、以下のように必要なルールをつなげて書きます。

Password::min(8)
    ->letters()
    ->mixedCase()
    ->numbers()
    ->symbols()
    ->uncompromised()

これを利用することで例えば、8文字以上の大文字小文字と数字と記号を利用したパスワードじゃないといけない、のようなものが簡単につくれますね。

入力確認用パスワードのチェック(confirmed)

Webサイトのパスワード入力するページは、よくパスワードと確認用にもう一度入力するフォームがあるかと思います。これをチェックするためにconfirmedというルールを利用すると楽です。

これは、そのパラメータが{field}_confirmationと同じであることを確認するというものです。

例えば、以下のようなバリデーションを作ってみます。

$request->validate([
    'password' => [
        'required',
        'confirmed',
        Password::min(8)
            ->mixedCase()
            ->numbers(),
    ],
]);

これはpasswordというパラメータのみしかチェックしてないように見えるのですが、実はpasswordpassword_confirmationと同じかどうかを確認しています。

$this->post('/password', [
    'password' => $password,
    'password_confirmation' => $password_confirmation,
]);

イメージ、上記のようなリクエストパラメータです。

ここで気をつけないといけないのが、password_confirmationではなく、password_confirmのようにリクエストパラメータ名を変えられないところです。

アプリケーション共通のパスワードルール

最近マージされた機能で、共通のパスワードルールを作成することができるようになりました。ドキュメントでいうデフォルトパスワードルールの定義と表現されているものです。バージョンは8.78.0以降利用可能です。

github.com

きっと一般的なWebサイトは、パスワードの入力をするAPIは1つではないと思います。例えば、新規登録時のパスワード入力とパスワードを忘れたときのパスワードの入力、のように、複数のURLでパスワードのリクエストを受け取る可能性があります。

各Controllerで毎回同じパスワードルールを定義するのはめんどくさいものです。ルールを変えたくなったらすべてのバリデーションのルールを変えるのは漏れが発生しそうです。

そこで、デフォルトパスワードルールを利用します。

$request->validate([
    'password' => [
        'required',
        'confirmed',
        Password::min(8)
            ->mixedCase()
            ->numbers(),
    ],
]);

この例でやってみたいと思います。

AppServiceProviderboot()に以下の処理を追加します。

    public function boot()
    {
        Password::defaults(fn() => Password::min(8)
            ->mixedCase()
            ->numbers());
    }

Passwordのdefaults()というメソッドにコールバック関数を渡してルールを定義しています。

Controllerに書いているバリデーションルールを以下のように書き換えます。

$request->validate([
    'password' => [
        'required',
        'confirmed',
        Password::default(),
    ],
]);

Passwordのdefault()を呼んでいるだけです。これだけで、置き換え完了です。

こうすることで、新規登録時の入力チェックとパスワードの再設定時の入力チェックのそれぞれの処理はPassword::default()と書いておき、AppServiceProvider側でルールを調整するだけで、全てのルールを変更することが可能になりメンテナンス性が向上しますね。

また、Passwordクラスの中身を読むと、required()sometimes()があるので、requiredやsometimesをバリデーションルール側に書く必要がなくなりそうです。

    /**
     * Get the default configuration of the password rule and mark the field as required.
     *
     * @return array
     */
    public static function required()
    {
        return ['required', static::default()];
    }

    /**
     * Get the default configuration of the password rule and mark the field as sometimes being required.
     *
     * @return array
     */
    public static function sometimes()
    {
        return ['sometimes', static::default()];
    }

最後に

以上のような便利な機能を利用すれば、各Controllerの開発時のパスワードの入力チェック処理は以下のように、パスワードルールを気にせずシンプルな書き方をするだけになります。

$request->validate([
    'password' => [
        'confirmed',
        Password::required(),
    ],
]);

パスワードルールを変更したいときだけ、ルールが書かれているAppServiceProviderを調整すれば良いだけになり、実装者は普段の開発ではパスワードルールを気にする必要がなくなりそうですね。

お問い合わせプライバシーポリシー制作物