1
votes

I've read many posts on how to force a user to create their own password once they log in for the first time, most of them are outdated ever since Laravel 5.4 came along (which I am using).

I am stuck on where to add my middleware to "catch" a new user logging in for the first time. I will be assigning users with temporary passwords, and once they enter the correct credentials in the login form, I want to redirect them to a page where they can create their own password. I do not want a user to be 'authenticated' until they DO create a password. Otherwise, if they try to go anywhere else, they will be sent back to the login page. I would rather not modify any of the base code in Laravel. So,

Would creating an Event be the best way to go?

Or if middleware should be used, where would I place my route? Between my guest middleware and my auth middleware? Here are my routes:

web.php

...
// Login Routes
Route::group(['prefix' => 'auth', 'namespace' => 'Admin\Auth'], function(){

    // Login Routes
    Route::get('login', 'LoginController@showLoginForm');
    Route::post('login', 'LoginController@login');
    Route::get('logout', 'LoginController@logout')->name('logout');


    // Password Reset Routes
    Route::get('password/reset', 'ForgotPasswordController@showLinkRequestForm')->name('password.request');
    Route::post('password/email', 'ForgotPasswordController@sendResetLinkEmail')->name('password.email');
    Route::get('password/reset/{token}', 'ResetPasswordController@showResetForm')->name('password.reset');
    Route::post('password/reset', 'ResetPasswordController@reset');
});

// Admin Routes
Route::group(['namespace' => 'Admin', 'prefix' => 'admin', 'middleware' => 'auth'], function () {

   // Business
    Route::get('/', function(){
        return view('admin.dashboard');
    });
    Route::get('profile', 'Settings\UserController@profile');


...
1

1 Answers

2
votes

The way I would go for it is no event, no middleware. Why? Because I, as a user, I may log in for the first time with the password you gave me, then you ask me to change my password. What if I don't to do it now, and close the window. I come back few hours or days later, It's not the FIRST TIME anymore, but the second time. If your logic relied on the first time logging in, then it won't catch me because it's the second time I am logging in with the default password.

I would go for a field that stores the default password I send to users. That means when you sign up, your password and default_password have the same values. And implement the check with a simple if at the login

if (Auth::attempt(['email' => $request->email, 'password' => $request->password])) {

    //User logged in... check for default password or 'old password'
    if (Hash::check(Auth::user()->default_password, Auth::user()->password)) {
        // default_password stored in plain text
        // The passwords match...
    }

    // Authentication passed...
    return redirect()->intended('dashboard');
}

The only downside here is that it will forever check for users still using their default password even after they have set their password already, but I don't think it will impact the performance of your application anyhow since it doesn't make any query.

Same thing if you have an event, you would still be checking all the time if they are in their first session or not. So basically same.

Updates

I would recommend to create an extra middleware for routes they can access after setting up their password. Because as soon as they are logged in, they can pass the auth middleware. You can make a middleware that only checks for the default password. That means you remove the password check logic from the login and put in the middleware instead. And protected your routes with that middleware.

Route::group(['middleware' => 'auth'], function(){
    Route::get('setup-password', function() {}); //only logged in user can set a password.

    Route::group(['middleware' => 'password'], function() {
        //Only users with a password can get in here.
    });
});

The password middleware checks for the password, else, kick them to 'setup-password' route

if (Hash::check(Auth::user()->default_password, Auth::user()->password)) {
    return redirect()->to('setup-password');
}
return $next($request);

Since the user is stored in the session, calling this middleware in every route will not, again, impact your performance. No query done.