StackBoot
1 year ago
356
4
Laravel

Custom guard in laravel

Posted 1 year ago by StackBoot

I have the following problem: I need to authenticate a user in my app through an external api so the user credentials are going to be checked in another api before authenticating the user in my app! I am not using a database to verify the user, I do not even have an eloquent user model, instead I have just a class User with props email, password. I have created the guard:

AuthServiceProvider

        Auth::extend('session', function ($app, $name, array $config) {
            return new CustomGuard(
                new UserProvider($app->make('App\Models\User\User')),
                $app->make('request')
            );
        });

Then I have created custom Guard like:

<?php

namespace App\Guards;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Http\Request;

class CustomGuard implements Guard
{
    /**
     * @var mixed
     */
    protected $request;
    /**
     * @var mixed
     */
    protected $provider;
    /**
     * @var mixed
     */
    protected $user;

    /**
     * Create a new authentication guard.
     *
     * @param  \Illuminate\Contracts\Auth\UserProvider  $provider
     * @param  \Illuminate\Http\Request  $request
     * @return void
     */
    public function __construct(UserProvider $provider, Request $request)
    {
        $this->request  = $request;
        $this->provider = $provider;
        $this->user     = null;
    }
    /**
     * Determine if the current user is authenticated.
     *
     * @return bool
     */
    public function check()
    {
        return !is_null($this->user());
    }

    /**
     * Determine if the current user is a guest.
     *
     * @return bool
     */
    public function guest()
    {
        return !$this->check();
    }

    /**
     * Get the currently authenticated user.
     *
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
     */
    public function user()
    {
        if (!is_null($this->user)) {
            return $this->user;
        }
    }

    /**
     * Get the Request params from the current request
     *
     * @return string
     */
    public function getRequestParams()
    {
        return $this->request->all();
    }

    /**
     * Get the ID for the currently authenticated user.
     *
     * @return string|null
     */
    public function id()
    {
        if ($user = $this->user()) {
            return $this->user()->getAuthIdentifier();
        }
    }

    /**
     * Validate a user's credentials.
     *
     * @return bool
     */
    public function validate(array $credentials = [])
    {
        if (empty($credentials['email']) || empty($credentials['password'])) {
            if (!$credentials = $this->getRequestParams()) {
                return false;
            }
        }

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

        if (!is_null($user) && $this->provider->validateCredentials($user, $credentials)) {
            $this->setUser($user);

            return true;
        } else {
            return false;
        }
    }

    /**
     * Set the current user.
     *
     * @param  Array $user User info
     * @return void
     */
    public function setUser(Authenticatable $user)
    {
        $this->user = $user;
        return $this;
    }
}

And the Custom User Provider where I inject that User model


<?php

namespace App\Extensions;

use App\Models\User\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
class UserProvider implements UserProvider
{
    /**
     * @var mixed
     */
    private $userModel;

    /**
     * @param User $user
     */
    public function __construct(User $user)
    {
        $this->userModel = $user;
    }

    /**
     * @param $identifier
     */
    public function retrieveById($identifier)
    {

    }
    /**
     * @param $identifier
     * @param $token
     */
    public function retrieveByToken($identifier, $token)
    {

    }
    /**
     * @param Authenticatable $user
     * @param $token
     */
    public function updateRememberToken(Authenticatable $user, $token)
    {

    }
    /**
     * @param array $credentials
     */
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials)) {
            return;
        }

        $user = $this->userModel->fetchUserByCredentials(['email' => $credentials['email']]);

        return $user;
    }
    /**
     * @param Authenticatable $user
     * @param array $credentials
     */
    public function validateCredentials(Authenticatable $user, array $credentials)
    {
        return ($credentials['email'] == $user->getAuthIdentifier()) &&
            ($credentials['password'] == $user->getAuthPassword());
    }
}


In my UserModel I inject my external service to authenticate the user and set the props currently values are hard coded as I want to make it work before I inject external servicer

class User extends Model implements Authenticatable
{
    use AuthTrait;
    /**
     * @var mixed
     */
    private $username;
    /**
     * @var mixed
     */
    public $password = 'test';
    /**
     * @var string
     */
    protected $rememberTokenName = 'remember_token';
    /**
     * @var mixed
     */
    public $email = '[email protected]';
    /**
     * @var mixed
     */
    protected $authenticated = false;
    /**
     * @var mixed
     */
    protected $role = null;

    /**
     * Fetch user by Credentials
     *
     * @param array $credentials
     * @return Illuminate\Contracts\Auth\Authenticatable
     */
    public function fetchUserByCredentials(array $credentials)
    {
        if ($this->email === $credentials['email']) {
            $arr_user = $this->email;
            return $this;
        }

        return null;
    }

The problem is that when I do in my controller :

    public function login(Request $request, Guard $guard)
    {
        $guard->validate();
        $user = $guard->user();
    
        dd($user);
   }

I get the user model and validation passes but now when I want to login the user :

auth()->attempt($user) I get message Call to undefined method App\Guards\CustomGuard::attempt() which I assume I need to add attempt() method in my custom guard, if so then how this method its going to look like ?

Please sign in or create an account to participate in this conversation.