User: password
- In this section, we implement the functionality for a user to update his password
REMARK
There is quite some similarity with the approach/code used in the previous section for updating/editing a user's profile
Preparation
Create controller
- Create a new controller class PasswordController.php in the folder app/Http/Controllers/User
- Run the command
php artisan make:controller User/PasswordController
- Run the command
- Add the methods
edit()
andupdate()
to the controller
class PasswordController extends Controller
{
// Edit user password
public function edit()
{
return view('user.password');
}
// Update and encrypt user password
public function update(Request $request)
{
// Validate $request
// Update encrypted user password in the database and redirect to previous page
return back();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Basic view
- Make a basic view password.blade.php inside this folder resources/views/user
- Open the file resources/views/user/password.blade.php and update the view
- The file contains a form and includes the shared alert sub-view to display feedback
@extends('layouts.template')
@section('title', 'Update password')
@section('main')
<h1>New password</h1>
@include('shared.alert')
<form action="/user/password" method="post">
@csrf
<div class="form-group">
<label for="current_password">Current password</label>
<input type="password" name="current_password" id="current_password"
class="form-control @error('current_password') is-invalid @enderror"
placeholder="Current password"
value="{{ old('current_password') }}"
required>
@error('current_password')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="password">New password</label>
<input type="password" name="password" id="password"
class="form-control @error('password') is-invalid @enderror"
placeholder="New password"
value="{{ old('password') }}"
minlength="8"
required>
@error('password')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label for="password_confirmation">Confirm new password</label>
<input type="password" name="password_confirmation" id="password_confirmation"
class="form-control"
placeholder="Confirm new password"
value="{{ old('password_confirmation') }}"
minlength="8"
required>
</div>
<button type="submit" class="btn btn-success">Update password</button>
</form>
@endsection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Add routes
- Open routes/web.php and add two new routes
- One GET route for showing the form
- One POST route for updating the password
Route::redirect('user', '/user/profile');
Route::middleware(['auth'])->prefix('user')->group(function () {
Route::get('profile', 'User\ProfileController@edit');
Route::post('profile', 'User\ProfileController@update');
Route::get('password', 'User\PasswordController@edit');
Route::post('password', 'User\PasswordController@update');
});
1
2
3
4
5
6
7
2
3
4
5
6
7
Form validation
- Add (server-side) form validation to PasswordController.php
- The current password (
current_password
) is required - The new password (
password
) is required, must be at least 8 characters long (min:8
) and must be confirmed
- The current password (
- If the validation fails, the user will automatically be redirected to the previous page
- If the validation is successful, the user will (also) be redirected back and a message is flashed to the session to be displayed on top of the page
public function update(Request $request)
{
// Validate $request
$this->validate($request,[
'current_password' => 'required',
'password' => 'required|min:8|confirmed',
]);
// Update encrypted user password in the database and redirect to previous page
session()->flash('success', 'Your password has been updated');
return back();
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
REMARKS
- For an input field to be confirmed, the field under validation must have a matching field with the postfix
_confirmation
- For example, if the field under validation is
password
, a matchingpassword_confirmation
field must be present in the form
- For example, if the field under validation is
- You don't need validation rules on the
password_confirmation
field- If the confirmation fails, the error will be displayed on the
password
field, not on thepassword_confirmation
field
- If the confirmation fails, the error will be displayed on the
REMARK
The values old('password')
and old('password_confirmation')
are empty/not working because Laravel protects the corresponding input fields (password
and password_confirmation
) and doesn't flash their values to the session!
Update the database
REMARKS
- Remember that the passwords (e.g.
user1234
) are hashed (with bcrypt) before they were inserted into the database - Notice that if the same password is hashed several times, the results will differ because a random salt (included in the resulting hash) is used in the bcrypt algorithm
- The hashed passwords look like this:
$2y$10$wLqY06r6o9itLGjIb6Jg6OF1.Ype94l2qdtICYZlf5sAt0kWprpra
.$2y
indicates the version of the used bcrypt algorithm, and$10
denotes the number of rounds. The rest of the hash string is the salt and the resulting hash itself.
- Find the logged in user by his id (
auth()->id()
) - Check if the hashed value of
$request->current_password
matches the value in the database ($user->password
) by using thecheck()
method on Laravel'sHash
facade- If not, send the user back with an error message
- If there is a match, use the method
make()
to hash$request->password
and save the result to the database
public function update(Request $request)
{
// Validate $request
$this->validate($request, [
'current_password' => 'required',
'password' => 'required|min:8|confirmed',
]);
// Update encrypted user password in the database and redirect to previous page
$user = User::findOrFail(auth()->id());
if (!Hash::check($request->current_password, $user->password)) {
session()->flash('danger', "Your current password doesn't mach the password in the database");
return back();
}
$user->password = Hash::make($request->password);
$user->save();
session()->flash('success', 'Your password has been updated');
return back();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
EXERCISE: Logout after password change (optional)
- Implement the following (alternative) behavior after a password is successfully changed:
- Log the user out
- Send him back to the login page