Laravelフォームリクエストを使用してパスワード検証を実装する方法
序章
Laravel フォームリクエストは、通常のリクエストクラスの機能を拡張する特別なクラスであり、高度な検証機能を有効にします。 フォームリクエストは、すべての検証ロジックをフォームリクエストクラスに移動できるため、コントローラーのアクションをよりクリーンに保つのにも役立ちます。 もう1つの利点は、コントローラーのアクションに到達する前にリクエストをフィルター処理できることです。
このガイドでは、管理領域にアクセスする前にユーザーにパスワードの確認を要求するパスワード検証手順を実装します。 この方法は二重チェックとして機能し、アプリケーションにセキュリティの追加レイヤーを提供します。
前提条件
このガイドをフォローアップするには、組み込みのLaravel認証が設定された動作するLaravel5.6以降のアプリケーションが必要です。 設定方法の詳細については、公式ドキュメントを確認してください。
ステップ1—ビューを作成する
まず、ユーザーのプロフィール編集ページを設定します。
このチュートリアルの執筆時点では、artisan
コマンドユーティリティはビューを生成しないため、ビューを手動で作成する必要があります。
ファイルresources/views/profile/edit.blade.php
を作成し、次のコードを追加します。
@extends('layouts.app')
@section('content')
<div class="container">
@if (session('info'))
<div class="row">
<div class="col-md-12">
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ session('info') }}
</div>
</div>
</div>
@elseif (session('error'))
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ session('error') }}
</div>
</div>
</div>
@endif
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Update Profile</div>
<div class="panel-body">
<form class="form-horizontal" method="POST" action="{{ route('profile.update', ['user' => $user]) }}">
{{ csrf_field() }}
{{ method_field('PUT') }}
<div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
<label for="name" class="col-md-4 control-label">Name</label>
<div class="col-md-6">
<input id="name" type="text" class="form-control" name="name" value="{{ $user->name }}">
@if ($errors->has('name'))
<span class="help-block">
<strong>{{ $errors->first('name') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label for="password" class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation">
</div>
</div>
<div class="form-group{{ $errors->has('current_password') ? ' has-error' : '' }}">
<label for="current-password" class="col-md-4 control-label">Current Password</label>
<div class="col-md-6">
<input id="current-password" type="password" class="form-control" name="current_password">
@if ($errors->has('current_password'))
<span class="help-block">
<strong>{{ $errors->first('current_password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Update
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
「プロファイルの編集」ページでは、info
およびerror
のフラッシュメッセージを確認し、ユーザーに表示します。
name
、password
、password_confirmation
、およびcurrent_password
フィールドがあります。
ユーザーが変更を加えるたびに、データベースに更新をコミットするために正しいcurrent_password
フィールドを指定する必要があります。
password
およびpassword_confirmation
フィールドを使用すると、ユーザーはパスワードを変更できます。 両方とも空のままにすると、ユーザーの現在のパスワードが保持され、保存されているパスワードは変更されません。
私たちの見解の主要なプレーヤーは、password
、password_confirmation
、およびcurrent_password
フィールドです。
name
フィールドについては、ケースを拡張してフィールドを追加するための例として役立ちます。
ステップ2—フォームリクエストを作成する
次に、このチュートリアルの最も重要な部分に移ります。
次のコマンドを実行して、フォームリクエストを作成します。
- php artisan make:request UpdateProfile
上記のコマンドは、app/Http/Requests/UpdateProfile.php
という名前のファイルを作成します。
このセクションのすべてのコード変更は、このファイルに対して行われます。
最初に行う必要があるのは、クラス宣言の前にエイリアスLaravelのハッシュファサードです。
use Illuminate\Support\Facades\Hash;
次に、フォームリクエストで承認を実行していないため、authorize
メソッドからtrue
を返す必要があります。
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
rulesメソッドは、このリクエストの検証ルールの概要を示す配列を返します。
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|max:255',
'password' => 'nullable|required_with:password_confirmation|string|confirmed',
'current_password' => 'required',
];
}
name
およびcurrent_password
のルールは一目瞭然です。
password
ルールでは、パスワードはconfirmed
宣言を使用して確認されると規定されています。
また、required_with:password_confirmation
も宣言されています。つまり、ユーザーがパスワードの確認を提供する場合は、パスワードも提供する必要があります。
これらの検証ルールは、コントローラーアクションでタイプヒントを入力すると(後で実行します)、要求ごとに自動的にチェックされます。
最後に行う必要があるのは、リクエストでwithValidator
メソッドを宣言することです。このメソッドは、検証ルールが実行される前に、完全に構築されたバリデーターインスタンスに渡されます。
/**
* Configure the validator instance.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
public function withValidator($validator)
{
// checks user current password
// before making changes
$validator->after(function ($validator) {
if ( !Hash::check($this->current_password, $this->user()->password) ) {
$validator->errors()->add('current_password', 'Your current password is incorrect.');
}
});
return;
}
withValdator
メソッド内に、after
フックを追加しました。これは、すべての検証チェックが行われた後に実行される関数です。
after
フックでは、ユーザーが提供したパスワードをデータベースに設定されたパスワードと比較しました。
$this->current_password
はcurrent_password
フォームフィールド値を提供しますが、Laravelは$this->user()
を使用して現在認証されているユーザーにアクセスできるため、$this->user()->password
は保存されたユーザーのハッシュパスワードを提供しますデータベース内。
2つのパスワードは、Hash
ファサードのcheck
メソッドを使用して比較されます。
ハッシュチェックが失敗した場合、 $validator->errors()->add('current_password', 'Your current password is incorrect.')
を使用して、キーcurrent_password
でバリデーターにエラーが追加されます。
これが完全なUpdateProfile
フォームリクエストです。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Hash;
class UpdateProfile extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|max:255',
'password' => 'nullable|required_with:password_confirmation|string|confirmed',
'current_password' => 'required',
];
}
/**
* Configure the validator instance.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
public function withValidator($validator)
{
// checks user current password
// before making changes
$validator->after(function ($validator) {
if ( !Hash::check($this->current_password, $this->user()->password) ) {
$validator->errors()->add('current_password', 'Your current password is incorrect.');
}
});
return;
}
}
ステップ3—コントローラーのセットアップ
フォームリクエストを使用するには、コントローラーアクションでタイプヒントを入力する必要があります。
次のコマンドを実行して、プロファイルコントローラを生成します。
- php artisan make:controller ProfileController
ファイルapp/Http/Controllers/ProfileController.php
を開き、次のコントローラーアクションを追加します。
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the form for editing the specified resource.
*
* @param \App\User $user
* @return \Illuminate\Http\Response
*/
public function edit(Request $request, User $user)
{
// user
$viewData = [
'user' => $user,
];
// render view with data
return view('profile.edit', $viewData);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\User $user
* @return \Illuminate\Http\Response
*/
public function update(UpdateProfile $request, User $user)
{
// form data
$data = $request->all();
$user->update($data);
return redirect(route('profile.edit', ['user' => $user]))
->with('info', 'Your profile has been updated successfully.');
}
プロファイルコントローラーのコンストラクターは、auth
ミドルウェアを設定して、ユーザーがプロファイルを編集する前にログインしていることを確認します。
edit
アクションは、ビューデータを使用してビューを提供しますが、update
アクションは、ユーザープロファイルを更新し、対応するフラッシュメッセージを使用してプロファイルの編集ページにリダイレクトします。
edit
アクションの署名に注意してください。ここでは、UpdateProfile
リクエストをタイプヒントしました。これは、UpdateProfile
フォームリクエスト内で検証を実行するために必要なすべてです。
また、コントローラークラス宣言の前に、フォームリクエストとユーザーモデルのエイリアスを作成する必要があります。
use App\Http\Requests\UpdateProfile;
use App\User;
ステップ4—保護されたルートとデータミューテーターの設定
ファイルapp/routes/web.php
を開き、次のコードを追加してコントローラーアクションを関連付けます。
Route::get('/profile/{user}/edit', 'ProfileController@edit')->name('profile.edit');
Route::put('/profile/{user}', 'ProfileController@update')->name('profile.update');
以前にフォームリクエストに追加した検証ルールに基づいて、null
パスワードが通過する可能性があります。
いかなる状況でも、ユーザー(またはアプリケーション開発者)はパスワードをnull
または空の文字列に設定することを望んでいません。
ユーザーパスワードが提供された場合にのみユーザーパスワードが設定されるようにするために、EloquentORMのミューテーターを使用します。
ファイルapp/User.php
を開き、次のコードを追加します。
// Only accept a valid password and
// hash a password before saving
public function setPasswordAttribute($password)
{
if ( $password !== null & $password !== "" )
{
$this->attributes['password'] = bcrypt($password);
}
}
頻繁なミューテーターは、命名スキームset<camel-cased-attribute-name>Attribute
に従う必要があります。
password
属性のミューテーターを宣言しているため、ミューテーターにsetPasswordAttribute
という名前を付けました。
ミューテイタ関数には、ミューテイタでは$password
変数である設定値が渡されます。
ミューテーターでは、$password
変数がnullまたは空の文字列でないかどうかを確認し、$this->attributes['password']
を使用してモデルに設定します。
また、パスワードは保存する前にハッシュされるため、アプリケーションの他の場所で行う必要はありません。
デフォルトのLaravelAuth/RegisterController
とAuth/ResetPasswordController
も、データベースに永続化する前にパスワードをハッシュするため、それぞれのコントローラーでcreate
とresetPassword
メソッドを更新する必要があります上記のミューテーターを宣言した後。
ファイルapp/Http/Controllers/Auth/RegisterController.php
を開き、次のコードを追加します。
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => $data['password'],
]);
}
ファイルapp/Http/Controllers/Auth/ResetPasswordController.php
を開き、次のコードを追加します。
/**
* Reset the given user's password.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param string $password
* @return void
*/
protected function resetPassword($user, $password)
{
$user->password = $password;
$user->setRememberToken(Str::random(60));
$user->save();
event(new PasswordReset($user));
$this->guard()->login($user);
}
ResetPasswordController
の場合、クラス宣言の前に使用されるそれぞれのクラスのエイリアスも必要になります。
use Illuminate\Support\Str;
use Illuminate\Auth\Events\PasswordReset;
これですべて完了し、パスワードの検証は期待どおりに機能します。
結論
このガイドでは、ユーザーが管理領域へのアクセスを許可されていることを表明するための追加のパスワード検証手順を実装する方法について説明しました。 Laravelアプリケーション内にフォーム検証を実装するためのフォームリクエストを作成および設定する方法を見てきました。
検証とフォームリクエストの詳細については、公式のLaravelドキュメントを確認してください。