使用 Laravel 5.4 和 Passport 进行多重身份验证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42331448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multi Auth with Laravel 5.4 and Passport
提问by Zubair1
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.
我正在尝试使用 Laravel Passport 设置多重身份验证,但它似乎不支持它。我正在使用密码授予来发布令牌,这要求我传递想要访问令牌的用户的用户名/密码。
I have 3 auth guards/providers setup, 4 in total. Users, Vendors, Admins and API
我有 3 个 auth 警卫/提供者设置,总共 4 个。用户、供应商、管理员和 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 providerand if its a vendor then the Vendor provider.
其中 2 个 Auth 需要通行证访问权限,因此每个用户都需要能够颁发令牌。但护照如果用户确实,则自动取API身份验证提供者,但我想这个基础来改变其用户在登录..用户提供,如果它的供应商,则供应商提供。
But the way Passport currently only supports only 1 user type, so its defaulting to the API provider.
但是 Passport 目前只支持 1 种用户类型,所以默认为API provider。
Is there something better for this? or should I go with roles based authentication instead.
有什么更好的方法吗?或者我应该改用基于角色的身份验证。
回答by Ricardo Fadini
If you still need.
如果你还需要。
I prefer go with roles, there is an amazing plugin for that: https://github.com/larapacks/authorization
我更喜欢使用角色,有一个很棒的插件: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).
您不是加载 PassportServiceProvider,而是创建自己的并扩展 PassportServiceProvider 并覆盖方法 makePasswordGrant。在此方法中,您将为自己的扩展存储库更改 Passport UserRepository。在用户存储库上,您必须更改动态模型的静态模型配置(我从请求属性加载,但您可以从任何地方获取)。
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.
PS:对不起,我的英语不好。
回答by Ghulam Ali
You have to modify the main library Files.
您必须修改主库文件。
1) File: vendor\laravel\passport\src\Bridge\UserRepository.php
1) 文件:vendor\laravel\passport\src\Bridge\UserRepository.php
Find getUserEntityByUserCredentialsand Copy the complete method and Paste this method below with name getEntityByUserCredentials.Donot modify the main function because it is used somewhere.
找到getUserEntityByUserCredentials并复制完整的方法并将此方法粘贴到下面,并命名为getEntityByUserCredentials。不要修改 main 函数,因为它在某处使用。
//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
2) 文件:vendor\league\oauth2-server\src\Grant\PasswordGrant.php
In the function validateUseradd the below code after line no. 88
在函数validateUser 中,在第 1 行之后添加以下代码。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
确保您已添加您的提供商并在 config/auth.php 中设置驱动程序
'guards' => [
'api_admins' => [
'driver' => 'passport',
'provider' => 'admins',
],
'api_vendors' => [
'driver' => 'passport',
'provider' => 'vendors',
],
I hope this helps.
我希望这有帮助。
回答by jsd
I have created a small package for this issue. Here's the link for the complete doc link
我为这个问题创建了一个小包。这是完整文档链接的链接
But the gist is, whenever a user
entity gets logged in, it checks for the guards and providers.
但要点是,每当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',
],
],
You should have a controller like this:
你应该有一个这样的控制器:
<?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');
}
}
and the request should be:
并且请求应该是:
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
To check in your controller who is the logged in user, you can do:
要检查作为登录用户的控制器,您可以执行以下操作:
auth()->guard('customers')->user()
auth()->guard('customers')->user()
回答by Hossein Karami
回答by Amirouche Zeggagh
if you look for solution to the Passport Multi-Auth APII recommend you this solution
回答by Niks
Laravel passport is only working with User as a provider. Even if you fetch token by adding above changes with PasswordGrant & UserRepository, while you go for API call for Post and get requests are not working with changed passport provider other than User.
Laravel 护照仅与作为提供者的用户合作。即使您通过使用 PasswordGrant 和 UserRepository 添加上述更改来获取令牌,当您为 Post 和 get 请求进行 API 调用时,也无法使用除 User 以外的已更改护照提供程序。
Better you create multi auth with session driver if must needed as Vendors and Customers. let 'User' model only for passport whose table columns supports admin, API, vendor, etc.
如果供应商和客户需要,最好使用会话驱动程序创建多重身份验证。让“用户”模型仅适用于其表列支持管理员、API、供应商等的护照。
Repo here laravel-multiAuth
在这里回购laravel-multiAuth