Home > Software engineering >  Why Laravel Auth::guard()->attempt() isn't working?
Why Laravel Auth::guard()->attempt() isn't working?

Time:12-28

So basically I generate users data after a payment, which it is saved in a table I created, it has a username and a encrypted password with Hash::make() method.

What I wanna do is to login with that data stored in the DB, so I made a guard.

This is the auth.php file with guards:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    'plataforma' => [
        'driver' => 'session',
        'provider' => 'usuario',
    ],
],

And these are the providers:

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
    'usuario' => [
        'driver' => 'eloquent',
        'model' => App\Models\Usuario::class,
    ],

This is the model:

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;


class Usuario extends Authenticatable
{
    use HasFactory;
    use Notifiable;

    protected $guard = 'plataforma';

    protected $fillable = [
        'nombre_usuario', 'correo', 'clave',
    ];

    protected $hidden = [
        'clave', 'remember_token',
    ];
}

And finally the controller:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;

class PlataformaController extends Controller
{
    public function login()
    {
        return view('web.plataforma-login');
    }

    public function autenticar(Request $request)
    {
        if (Auth::guard('plataforma')->attempt(['nombre_usuario' => $request->input('nombre_usuario'), 'clave' => $request->input('clave')])) {
            return view('web.plataforma');
        } else {
            dd(Auth::guard('plataforma')->attempt(['nombre_usuario' => $request->input('nombre_usuario'), 'clave' => $request->input('clave')]));
        }
    }

    public function dashboard()
    {
        return view('web.plataforma');
    }
}

So basically the Auth::guard('plataforma')->attempt(...) returns false, I already checked that the values of $request->input(...) are correct, I checked that the encrypted password in the DB is the same as the password that the user enter with Hash::check(), so I don't know what is wrong and I'm so confused...

I spent a lot of time reading other questions with no solutions either, I would be glad if anyone can help me out.

CodePudding user response:

After reading the API, I've come to the conclusion attempt() is not working to you because you're using a different password column name.

The following is the attempt function's code from the Illuminate\Auth\SessionGuard class:

/**
 * Attempt to authenticate a user using the given credentials.
 *
 * @param  array  $credentials
 * @param  bool  $remember
 * @return bool
 */
public function attempt(array $credentials = [], $remember = false)
{
    $this->fireAttemptEvent($credentials, $remember);

    $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);

    // If an implementation of UserInterface was returned, we'll ask the provider
    // to validate the user against the given credentials, and if they are in
    // fact valid we'll log the users into the application and return true.
    if ($this->hasValidCredentials($user, $credentials)) {
        $this->login($user, $remember);

        return true;
    }

    // If the authentication attempt fails we will fire an event so that the user
    // may be notified of any suspicious attempts to access their account from
    // an unrecognized user. A developer may listen to this event as needed.
    $this->fireFailedEvent($user, $credentials);

    return false;
}

The key functions here are retrieveByCredentials and hasValidCredentials

Here's retrieveByCredentials from Illuminate\Auth\EloquentUserProvider. As you can see, it's excluding the 'password' key from the query in the foreach.

/**
 * Retrieve a user by the given credentials.
 *
 * @param  array  $credentials
 * @return \Illuminate\Contracts\Auth\Authenticatable|null
 */
public function retrieveByCredentials(array $credentials)
{
    if (empty($credentials) ||
       (count($credentials) === 1 &&
        → Str::contains($this->firstCredentialKey($credentials), 'password'))) { ←
        return;
    }

    // First we will add each credential element to the query as a where clause.
    // Then we can execute the query and, if we found a user, return it in a
    // Eloquent User "model" that will be utilized by the Guard instances.
    $query = $this->newModelQuery();

    foreach ($credentials as $key => $value) {
        → if (Str::contains($key, 'password')) { ←
            continue;
        }

        if (is_array($value) || $value instanceof Arrayable) {
            $query->whereIn($key, $value);
        } elseif ($value instanceof Closure) {
            $value($query);
        } else {
            $query->where($key, $value);
        }
    }

    return $query->first();
}

Here's hasValidCredentials from Illuminate\Auth\EloquentUserProvider. The key function here is validateCredentials

/**
 * Determine if the user matches the credentials.
 *
 * @param  mixed  $user
 * @param  array  $credentials
 * @return bool
 */
protected function hasValidCredentials($user, $credentials)
{
    $validated = ! is_null($user) && $this->provider->validateCredentials($user, $credentials);

    if ($validated) {
        $this->fireValidatedEvent($user);
    }

    return $validated;
}

Here's validateCredentials from the Illuminate\Auth\EloquentUserProvider class. You can see it's again, using by default 'password' as the key name. Let's see what getAuthPassword() looks like.

/**
 * Validate a user against the given credentials.
 *
 * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
 * @param  array  $credentials
 * @return bool
 */
public function validateCredentials(UserContract $user, array $credentials)
{
    → $plain = $credentials['password']; ←

    return $this->hasher->check($plain, $user->getAuthPassword());
}

And finally getAuthPassword from the Illuminate\Auth\Authenticatable class. It's just returning the model's 'password' attribute.

/**
 * Get the password for the user.
 *
 * @return string
 */
public function getAuthPassword()
{
    → return $this->password; ←
}



Basically, if you want this to work, you need to change a few things about your code.

  1. Use password as the key in attempt()
public function autenticar(Request $request)
{
    $attempt = Auth::guard('plataforma')->attempt([
        'nombre_usuario' => $request->input('nombre_usuario'),
        'password' => $request->input('clave')
    ]);

    if ($attempt) {
        return view('web.plataforma');
    } else {
        dd($attempt);
    }
}
  1. Override your Authenticatable model (Usuario)'s getAuthPassword method.
# Usuario model
/**
 * Get the password for the user.
 *
 * @return string
 */
public function getAuthPassword()
{
    return $this->clave;
}
  • Related