5
votes

I'm creating a small app using Laravel 5.3. I've applied user activation (via email confirmation) on Laravel's default Auth. But i couldn't find a way to stop sending password reset link if account/user not activated by verifying email address. Currently if a user creates an account and doesn't verify the email address he/she can login using Password Reset link.

this what i've in user table

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name')->nullable();;
        $table->string('username')->unique();
        $table->string('email')->unique();
        $table->string('company')->nullable();;
        $table->string('password');
        $table->boolean('activated')->default(false);
        $table->rememberToken();
        $table->timestamps();
    });

    Schema::create('user_activations', function (Blueprint $table) {
        $table->integer('user_id')->unsigned();
        $table->string('token')->index();
        $table->timestamp('created_at');
    });
}

UPDATE I tried to do it by updating the below function. but it's not working

public function reset(Request $request)
{
    if (!$request->activated) {
        return redirect('/');
    } else {
        $this->validate($request, $this->rules(), $this->validationErrorMessages());

        $response = $this->broker()->reset(
            $this->credentials($request), function ($user, $password) {
                $this->resetPassword($user, $password);
            }
        );

        return $response == Password::PASSWORD_RESET
                    ? $this->sendResetResponse($response)
                    : $this->sendResetFailedResponse($request, $response);
    }
}
3

3 Answers

6
votes

I found the solution. Just in case if someone looking for the same solution. Here is the function i overridden

public function sendResetLinkEmail(Request $request)
{
    $this->validate($request, ['email' => 'required|email']);
    $user_check = User::where('email', $request->email)->first();

    if (!$user_check->activated) {
        return back()->with('status', 'Your account is not activated. Please activate it first.');
    } else {
        $response = $this->broker()->sendResetLink(
            $request->only('email')
        );

        if ($response === Password::RESET_LINK_SENT) {
            return back()->with('status', trans($response));
        }

        return back()->withErrors(
            ['email' => trans($response)]
        );
    }
} 
1
votes

Another solution is to overwrite the sendPasswordResetNotification in your User Model:

/**
 * OVERWRITE ORIGINAL
 * @param string $token
 */
public function sendPasswordResetNotification($token) {
  if(!$this->active){
    session()->flash('error', 'Your account is disabled.');
    return back();
  }

  $this->notify(new \Illuminate\Auth\Notifications\ResetPassword($token));
}

If the user is not activated, he won't get another email. Instead, he will be returned back to the login page with an error message in the session. To show it you need something like this in your blade file:

@if ($errors->any())
@foreach ($errors->all() as $message)
  <div class="alert alert-danger-plain">
    <i class="icon-exclamation"></i> {{ $message }}
  </div>
@endforeach
@endif
0
votes

Another straightforward way is to create a new validation rule to check if the user account is activated, And then add the rule to the validateEmail method inside the ForgotPasswordController. Just make sure that you delete the password token everytime you deactivate a user.

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use App\User;

class ActiveUser implements Rule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $user = User::whereEmail($value)->first();
        if($user) {
            if($user->active) {
                return true;
            }
            return false;
        }
        return true;
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'Your account is deactivated.';
    }
}

And in the ForgotPasswordController

/**
 * Validate the email for the given request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return void
 */
protected function validateEmail(Request $request)
{
    $this->validate($request, ['email' => [ 'required', 'email', new ActiveUser ]]);
}

And this is how to delete the token at any user deactivation.

$user = \App\user::find(1);
\Illuminate\Support\Facades\Password::broker()->deleteToken($user);