2017-02-19 99 views
3

我正在嘗試使用Laravel Passport設置多重身份驗證,但它似乎並不支持它。我正在使用密碼授予發出令牌,這需要我傳遞想要訪問令牌的用戶的用戶名/密碼。Laravel 5.4和Passport的多重身份驗證

我有3個身份驗證警衛/提供者設置,共4個。 用戶,供應商,管理員和API

AUTHS 2護照需要訪問,所以每個用戶都需要能夠發出令牌。但是Passport會自動獲取API授權提供程序,但我希望根據哪個用戶正在登錄進行更改。如果用戶確實那麼用戶提供程序以及它的供應商,然後是供應商提供商

但Passport目前的方式,它只支持1個用戶類型,所以它默認爲API提供商

有什麼更好的嗎?或者我應該使用基於角色的身份驗證來代替。

回答

3

如果您仍然需要。

我更喜歡去的角色,對於這一個驚人的插件:https://github.com/larapacks/authorization

但是如果你出於某種原因需要這一點,你就可以使用下面的執行下列步驟。

對於多守衛,您將不得不覆蓋一些代碼。

不是加載PassportServiceProvider,而是創建自己的並擴展PassportServiceProvider並覆蓋makePasswordGrant方法。 在此方法中,您將更改自己的擴展存儲庫的Passport UserRepository。在用戶資源庫中,您必須更改靜態模型配置以獲取動態配置(我從請求屬性加載,但您可以從任何地方獲取)。

你可能不得不重寫別的東西,但我做了一個測試並且工作。

例:

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:對不起我的英語不好。

2

您必須修改主庫文件。

1)文件:供應商\ laravel \護照的\ src \橋\ UserRepository.php

查找getUserEntityByUserCredentials和複製完整的方法和下面的名字getEntityByUserCredentials這種方法粘貼。 Donot修改主函數,因爲它在某處使用。

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

那麼,在新的複製功能,找到如下:

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

,取而代之的是:

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

2)文件:供應商\聯賽\的oauth2服務器\ src \ Grant \ PasswordGrant.php

在功能validateUser在行號後添加下面的代碼。 88

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

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

添加具有

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

將以下代碼後,現在試試這個使用郵遞員

在輸入字段中添加提供商場像

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

化妝確定你已經添加你的提供者並設置驅動程序在配置/ auth.php

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

我希望這可以幫助。

0

Laravel護照只與用戶作爲提供者一起工作。即使您通過PasswordGrant & UserRepository添加上述更改來獲取令牌,但您需要進行Post調用的API調用,並且請求不能與除User以外的更改的護照提供程序一起使用。

如果作爲供應商和客戶需要,您最好使用會話驅動程序創建多重身份驗證。只讓護照,其表列支持管理,API,供應商的「用戶」模型等

回購這裏laravel-multiAuth

0

我創建了一個小型封裝針對此問題。以下是完整文檔的鏈接link

但是要點是,無論何時user實體登錄,它都會檢查警衛和提供者。

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

    'api' => [ 
     'driver' => 'passport', 
     'provider' => 'users', 
    ], 

    'customers' => [ 
     'driver' => 'passport', 
     'provider' => 'customers' 
    ], 
], 

'providers' => [ 
    'users' => [ 
     'driver' => 'eloquent', 
     'model' => 'App\User', 
    ], 
    /** 
    * This is the important part. You can create as many providers as you like but right now, 
    * we just need the customer 
    */ 
    'customers' => [ 
     'driver' => 'eloquent', 
     'model' => 'App\Customer', 
    ], 
], 

你應該有一個這樣的控制器:

<?php 

namespace App\Http\Controllers\Auth; 

use App\Customers\Customer; 
use App\Customers\Exceptions\CustomerNotFoundException; 
use Illuminate\Database\ModelNotFoundException; 
use Laravel\Passport\Http\Controllers\AccessTokenController; 
use Laravel\Passport\TokenRepository; 
use League\OAuth2\Server\AuthorizationServer; 
use Psr\Http\Message\ServerRequestInterface; 
use Lcobucci\JWT\Parser as JwtParser; 

class CustomerTokenAuthController extends AccessTokenController 
{ 
    /** 
     * The authorization server. 
     * 
     * @var \League\OAuth2\Server\AuthorizationServer 
     */ 
    protected $server; 

    /** 
     * The token repository instance. 
     * 
     * @var \Laravel\Passport\TokenRepository 
     */ 
    protected $tokens; 

    /** 
     * The JWT parser instance. 
     * 
     * @var \Lcobucci\JWT\Parser 
     */ 
    protected $jwt; 

    /** 
     * Create a new controller instance. 
     * 
     * @param \League\OAuth2\Server\AuthorizationServer $server 
     * @param \Laravel\Passport\TokenRepository $tokens 
     * @param \Lcobucci\JWT\Parser $jwt 
     */ 
    public function __construct(AuthorizationServer $server, 
           TokenRepository $tokens, 
           JwtParser $jwt) 
    { 
     parent::__construct($server, $tokens, $jwt); 
    } 

    /** 
     * Override the default Laravel Passport token generation 
     * 
     * @param ServerRequestInterface $request 
     * @return array 
     * @throws UserNotFoundException 
     */ 
    public function issueToken(ServerRequestInterface $request) 
    { 
     $body = (parent::issueToken($request))->getBody()->__toString(); 
     $token = json_decode($body, true); 

     if (array_key_exists('error', $token)) { 
      return response()->json([ 
       'error' => $token['error'], 
       'status_code' => 401 
      ], 401); 
     } 

     $data = $request->getParsedBody(); 

     $email = $data['username']; 

     switch ($data['provider']) { 
      case 'customers'; 

       try { 

       $user = Customer::where('email', $email)->firstOrFail(); 

       } catch (ModelNotFoundException $e) { 
        return response()->json([ 
         'error' => $e->getMessage(), 
         'status_code' => 401 
        ], 401); 
       } 

       break; 

      default : 

       try { 

       $user = User::where('email', $email)->firstOrFail(); 

       } catch (ModelNotFoundException $e) { 
        return response()->json([ 
         'error' => $e->getMessage(), 
         'status_code' => 401 
        ], 401); 
       }   
     } 

     return compact('token', 'user'); 
    } 
} 

和要求應該是:

POST /api/oauth/token HTTP/1.1 
Host: localhost 
Content-Type: application/x-www-form-urlencoded 
Cache-Control: no-cache 

grant_type=password&username=test%40email.com&password=secret&provider=customers 

要檢查您的控制器是誰登錄的用戶,你可以做:

auth()->guard('customers')->user()