首页 文章

使用Laravel 5.4和Passport进行Multi Auth

提问于
浏览
4

我正在尝试使用Laravel Passport设置多个auth,但它似乎不支持它 . 我使用密码授予发出令牌,要求我传递想要访问令牌的用户的用户名/密码 .

我有3个auth警卫/提供者设置,总共4个 . 用户,供应商,管理员和API

其中2个Auths需要访问护照,因此每个用户都需要能够发放令牌 . 但Passport会自动获取API身份验证提供程序,但我希望根据登录的用户进行更改 . 如果用户执行了用户提供程序,如果是供应商,那么就是供应商提供程序 .

但Passport目前只支持1种用户类型,因此默认为API提供者 .

这有什么更好的吗?或者我应该使用基于角色的身份验证 .

4 回答

  • 1

    您必须修改主库文件 .

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

    找到 getUserEntityByUserCredentials 并复制完整方法并在下面粘贴此方法,名称为 getEntityByUserCredentials. 不要修改主函数,因为它在某处使用 .

    //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) File: vendor\league\oauth2-server\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
        );
    

    Now try this using postman

    在输入字段中添加提供程序字段,如

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

    确保已添加提供程序并在config / auth.php中设置驱动程序

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

    我希望这有帮助 .

  • 3

    Laravel护照仅与用户一起提供 . 即使您通过使用PasswordGrant和UserRepository添加上述更改来获取令牌,当您为Post发送API调用时,获取请求也不适用于除User之外的已更改的护照提供程序 .

    如果必须作为供应商和客户需要,最好使用会话驱动程序创建多个auth . 让'User'模型仅用于表列支持admin,API,vendor等的护照 .

    回购这里laravel-multiAuth

  • 5

    如果你还需要 .

    我更喜欢使用角色,有一个惊人的插件:https://github.com/larapacks/authorization

    但是如果你以某种方式需要它,你将能够按照下面的步骤使用 .

    对于多重防护,您将不得不覆盖一些代码 .

    您不必加载PassportServiceProvider,而是创建自己的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:对不起,我的英文不好 .

  • 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()

相关问题