Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi Auth with Laravel 5.4 and Passport

I am trying to setup multi auth with Laravel Passport, but it doesn't seem to support it. I am using the Password Grant to issue tokens which requires me to pass username/password of the user wanting access tokens.

I have 3 auth guards/providers setup, 4 in total. Users, Vendors, Admins and API

2 of the Auths need passport access, so each user needs to be able to issue tokens. But Passport automatically takes the API auth provider, but I want this to change based on which user is logging in.. If user does then the User provider and if its a vendor then the Vendor provider.

But the way Passport currently only supports only 1 user type, so its defaulting to the API provider.

Is there something better for this? or should I go with roles based authentication instead.

like image 450
Zubair1 Avatar asked Feb 19 '17 18:02

Zubair1


2 Answers

If you still need.

I prefer go with roles, there is an amazing plugin for that: https://github.com/larapacks/authorization

But if you somehow needs that, you will be able to use following the steps bellow.

For multi guards, you will have to overwrite some code.

Instead of loading PassportServiceProvider, you create your own and extends the PassportServiceProvider and overwrites the method makePasswordGrant. On this method, you will change the Passport UserRepository for your own repository extended. On user repository you must to change the static model config for a dynamic one (I load from request attributes, but you can get from anywhere).

You may have to overwrite something else, but I made a test and works.

Ex:

PassportServiceProvider

namespace App\Providers;

use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Grant\PasswordGrant;
use Laravel\Passport\PassportServiceProvider as BasePassportServiceProvider;
use Laravel\Passport\Passport;

class PassportServiceProvider extends BasePassportServiceProvider
{
    /**
     * Create and configure a Password grant instance.
     *
     * @return PasswordGrant
     */
    protected function makePasswordGrant()
    {
        $grant = new PasswordGrant(
            $this->app->make(\App\Repositories\PassportUserRepository::class),
            $this->app->make(\Laravel\Passport\Bridge\RefreshTokenRepository::class)
        );

        $grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());

        return $grant;
    }

}

UserRepository

namespace App\Repositories;

use App;
use Illuminate\Http\Request;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use Laravel\Passport\Bridge\UserRepository;
use Laravel\Passport\Bridge\User;
use RuntimeException;

class PassportUserRepository extends UserRepository
{
    /**
     * {@inheritdoc}
     */
    public function getUserEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity)
    {
        $guard = App::make(Request::class)->attributes->get('guard') ?: 'api';
        $provider = config("auth.guards.{$guard}.provider");


        if (is_null($model = config("auth.providers.{$provider}.model"))) {
            throw new RuntimeException('Unable to determine user model from configuration.');
        }


        if (method_exists($model, 'findForPassport')) {
            $user = (new $model)->findForPassport($username);
        } else {
            $user = (new $model)->where('email', $username)->first();
        }


        if (! $user ) {
            return;
        } elseif (method_exists($user, 'validateForPassportPasswordGrant')) {
            if (! $user->validateForPassportPasswordGrant($password)) {
                return;
            }
        } elseif (! $this->hasher->check($password, $user->password)) {
            return;
        }

        return new User($user->getAuthIdentifier());
    }
}

PS: Sorry my bad english.

like image 94
Ricardo Fadini Avatar answered Nov 11 '22 22:11

Ricardo Fadini


You have to modify the main library Files.

1) File: vendor\laravel\passport\src\Bridge\UserRepository.php

Find getUserEntityByUserCredentials and Copy the complete method and Paste this method below with name getEntityByUserCredentials. Donot modify the main function because it is used somewhere.

//Add the $provider variable at last or replace this line.
public function getEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity, $provider)

Then, in the new duplicated function, find the below:

$provider = config('auth.guards.api.provider');

and Replace it with:

$provider = config('auth.guards.'.$provider.'.provider');

2) File: vendor\league\oauth2-server\src\Grant\PasswordGrant.php

In the function validateUser add the below code after line no. 88

$provider = $this->getRequestParameter('provider', $request);

if (is_null($provider)) {
     throw OAuthServerException::invalidRequest('provider');
}

After adding replace the following code with

$user = $this->userRepository->getEntityByUserCredentials(
        $username,
        $password,
        $this->getIdentifier(),
        $client,
        $provider
    );

Now try this using postman

Add the provider field in your input field like

provider = api_vendors
OR
provider = api_admins
OR
provider = api_users
And so on....

make sure you have added your provider and set the drivers in the config/auth.php

'guards' => [
 'api_admins' => [
    'driver' => 'passport',
    'provider' => 'admins',
  ],
  'api_vendors' => [
    'driver' => 'passport',
    'provider' => 'vendors',
  ],

I hope this helps.

like image 44
Ghulam Ali Avatar answered Nov 11 '22 22:11

Ghulam Ali