Home > Net >  Let Users and Clients share the same authentication
Let Users and Clients share the same authentication

Time:06-03

I am using Laravel Breeze. My App will have two access sites:

  1. Admins can login related to the users table (working)
  2. Clients can login related to the clients table (to be discussed)

I don't know, if this is a good idea, but I want to share the already implemented Auth Service with another Model: clients.

What I already implemented is:

  • Logged in user can create a client
  • Client receives a email verification email from an event
  • Client can confirm email address and will be redirect to the login view

Now it becomes tricky for me. The AuthenticatedSessionController::store() method is checking for the $request->authenticate() and this runs agains the users table and fails for the clients table. I slightly modified the method to redirect based on the type of login candidate:

public function store(LoginRequest $request)
    {
        $request->authenticate();
        
        $request->session()->regenerate();

        $user = User::where('id', Auth::id())->first();
        if ( $user ) {
            return redirect()->intended(RouteServiceProvider::HOME);
        }

        $client = Client::where('id', Auth::id())->findOrFail();
        if ( $client ) {
            return redirect()->to('portal.show', $client->id);
        }
    }

but this works for users only as $request->authenticate() will not let clients in. Now I need support and from here on I'm just guessing that the next step is the update I did in config/auth.php:

return [
    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
        'clients' => [
            'driver' => 'eloquent',
            'model' => App\Models\Client::class,
        ],
    ],
    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        'clients' => [
            'provider' => 'clients',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],
    'password_timeout' => 10800,

];

CodePudding user response:

You will need to look into & modify authenticate method of App\Http\Requests\Auth\LoginRequest class.

One way of doing it could be to check for presence of email received via request against users and clients tables.

Then if the email belongs to a client - implement custom logic to validate credentials against clients table records and login the client

And if the email belongs to user - then let the request pass through as normal

Eg:

public function authenticate()
{
    $type = DB::table('clients')->where('email', $this->email)->exists() ? 'client' : 'user';

    if($type === 'user') {
        return $this->authenticateUser();
    }

    //Validate credentials against `clients` table 
    // If valid retrieve the client and login the client 
    //Else throw ValidationException
}

//Copy the content of original authenticate to this method
protected function authenticateUser()
{

    $this->ensureIsNotRateLimited();

    if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
    RateLimiter::hit($this->throttleKey());

        throw ValidationException::withMessages([
            'email' => trans('auth.failed'),
        ]);
    }

    RateLimiter::clear($this->throttleKey());
}

NOTE With this approach you are not doing any rate-limiting/throttling nor firing attempt events

For complete robust authentication system for clients, I guess it will be required to define a separate guard, user provider and then re-implement SessionGuard functionality all over again.

Another wild thought which comes to mind is, why not have Client be represented as a record on users table just for authentication purpose and may be have a one-to-one relation between them.

  • Related