Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.0] Passport Multi-Auth #987

Closed
wants to merge 1 commit into from

Conversation

afilippov1985
Copy link
Contributor

Shortly:

  1. I added middleware that calls app('auth')->shouldUse($guard)
  2. Changed Laravel\Passport\Bridge\UserRepository so it can get users from registered user providers (not only from EloquentUserProvider)

Full setup example:

// app/ApiUser.php
// user model for 'myguard1' guard ('eloquent' user provider)
<?php

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class ApiUser extends Authenticatable
{
    use HasApiTokens, Notifiable;

    protected $table = 'users';
    
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
    
    public function validateForPassportPasswordGrant($password)
    {
        return true;
    }
}
// app/MyUser2.php
// user model for 'myguard2' guard (custom user provider)
<?php
namespace App;

use Illuminate\Auth\GenericUser;
use Illuminate\Contracts\Support\Arrayable;
use Laravel\Passport\HasApiTokens;

class MyUser2 extends GenericUser implements Arrayable
{
    use HasApiTokens;

    public function toArray()
    {
        return $this->attributes;
    }
}
// app/MyUserProvider2.php
// custom user provider
<?php
namespace App;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider as UserProviderContract;

class MyUserProvider2 implements UserProviderContract
{
    public function retrieveById($identifier)
    {
        if ($identifier == 555) {
            return new MyUser2([
                'id' => $identifier,
                'password' => '',
                'remember_token' => '',
                'email' => 'ccc@ccc.ccc',
            ]);
        }
        return null;
    }
    
    public function retrieveByToken($identifier, $token)
    {
        return null;
    }
    
    public function updateRememberToken(Authenticatable $user, $token)
    {
    }
    
    public function retrieveByCredentials(array $credentials)
    {
        return null;
    }
    
    public function validateCredentials(Authenticatable $user, array $credentials)
    {
        return true;
    }
}

Register user provider in AuthServiceProvider.php

// app/Providers/AuthServiceProvider.php
    public function boot()
    {
        // ..........

        $this->app['auth']->provider('userprovider2', function ($app, array $config) {
            return new \App\MyUserProvider2();
        });

    }

Add guards and providers in auth.php

// config/auth.php

    'guards' => [
        // ............
        'myguard1' => [
            'driver' => 'passport',
            'provider' => 'userprovider1',
        ],
        'myguard2' => [
            'driver' => 'passport',
            'provider' => 'userprovider2',
        ],
    ],
    'providers' => [
        // .............
        'userprovider1' => [
            'driver' => 'eloquent',
            'model' => App\ApiUser::class,
        ],
        'userprovider2' => [
            'driver' => 'userprovider2',
        ],
    ],

Add resource routes

// routes/api.php
Route::middleware(['auth:myguard1'])->get('test1', function(Request $request) {
    return response()->json($request->user());
});

Route::middleware(['auth:myguard2'])->get('test2', function(Request $request) {
    return response()->json($request->user());
});

Now you have two options:

Option 1: You want individual URL per guard
Add routes (one for each guard)

// config/api.php
Route::group(['middleware' => ['throttle', 'passport.guard:myguard1']], function() {
    Route::post('/token1', '\Laravel\Passport\Http\Controllers\AccessTokenController@issueToken');
});

Route::group(['middleware' => ['throttle', 'passport.guard:myguard2']], function() {
    Route::post('/token2', '\Laravel\Passport\Http\Controllers\AccessTokenController@issueToken');
});

Option 2: You want to pass guard name in POST request like this

$post = http_build_query([
    'grant_type' => 'password',
    'client_id' => '3',
    'client_secret' => '..............................',
    'username' => 'aaa@aaa.aaa',
    'password' => '12345',
    'guard' => 'myguard1',
]);

Add some code to AuthServiceProvider.php

// app/Providers/AuthServiceProvider.php
    public function boot()
    {
        // ...........
        Passport::routes();

        // this callback will be called in middleware
        Passport::setGuardResolver(function($request, $param) {
            $guard = $request->input('guard');
            // whitelist filter
            if (!in_array($guard, ['myguard1', 'myguard2'], true)) {
                return $param; // `api` guard
            }
            return $guard;
        });
    }

That's all.

@driesvints driesvints changed the title Passport Multi-Auth [7.0] Passport Multi-Auth Mar 12, 2019
@taylorotwell
Copy link
Member

I am closing this pull request because it lacks sufficient explanation, tests, or both. It is difficult for us to merge pull requests without these things because the change may introduce breaking changes to the framework.

Feel free to re-submit your change with a thorough explanation of the feature and tests - integration tests are preferred over unit tests. Please include it's benefit to end users; the reasons it does not break any existing features; how it makes building web applications easier, etc.

Please do not just share large code snippets, share a full paragraph explaining the use-case and benefits to end users.

Thanks!

@afilippov1985
Copy link
Contributor Author

This code was not intended to be merged.
It's just for discussion of one of possible implementations.

@driesvints
Copy link
Member

@afilippov1985 we only accept finished prs. If you want to discuss a possible implementation it's best to do that in the related issue first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants