自定义 Laravel 护照检查
Custom Laravel Passport Check
是否可以向 findForPassport 添加或再传递 1 个变量?
默认 laravel 护照登录,我只能传递 2 个变量(用户名、密码),但我想再传递 1 个变量并在 findForPassport 中检查该用户是否属于其他 table还是不是。
希望这个回答能对其他人有所帮助。
如果要添加变量并将此变量传递给 User Authenticate 模型中的 findPassport 函数,则需要更新 passport 中的 3 class :
- UserRepositoryInterface 在 vendor\league\oauth2-server\src\Repositories\UserRepositoryInterface
- PasswordGrant 在 vendor\league\oauth2-server\src\Grant\PasswordGrant
- UserRepository 在 vendor\laravel\passport\src\Bridge\UserRepository
在示例代码中,我将添加父变量,代码将如下所示
+在 UserRepositoryInterface class
interface UserRepositoryInterface extends RepositoryInterface
{
/**
* Get a user entity.
*
* @param string $username
* @param string $password
* @param string $grantType The grant type used
* @param ClientEntityInterface $clientEntity
*
* @return UserEntityInterface
*/
public function getUserEntityByUserCredentials(
$username,
$password,
$parent, <------variable example
$grantType,
ClientEntityInterface $clientEntity
);
}
+在 PasswordGrant class
class PasswordGrant extends AbstractGrant{
protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)
{
$username = $this->getRequestParameter('username', $request);
if (is_null($username)) {
throw OAuthServerException::invalidRequest('username');
}
$password = $this->getRequestParameter('password', $request);
if (is_null($password)) {
throw OAuthServerException::invalidRequest('password');
}
/**
* Get a user parent.
* varaible example
*/
$parent = $this->getRequestParameter('parent', $request);
if (is_null($parent)) {
throw OAuthServerException::invalidRequest('password');
}
$user = $this->userRepository->getUserEntityByUserCredentials(
$username,
$password,
$parent, <--- variable example get from request
$this->getIdentifier(),
$client
);
if ($user instanceof UserEntityInterface === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidCredentials();
}
return $user;
} }
+在 UserRepository class
class UserRepository implements UserRepositoryInterface
{
public function getUserEntityByUserCredentials($username, $password, $parent, $grantType, ClientEntityInterface $clientEntity)
/*add 1more parameter that implement from UserRepositoryInterface*/
{
$provider = config('auth.guards.api.provider');
if (is_null($model = config('auth.providers.'.$provider.'.model'))) {
throw new RuntimeException('Unable to determine authentication model from configuration.');
}
if (method_exists($model, 'findForPassport')) {
$user = (new $model)->findForPassport($username,$parent); <--- finally we pass parent variable to findForPassport here
} 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->getAuthPassword())) {
return;
}
return new User($user->getAuthIdentifier());
}
}
然后您可以从 findForPassport 中的参数中获取 $parent 值。但请确保您的 return 值为 eloquent 用户。如果您想加入 table,您可以查看我的下面的示例代码
class User extends Authenticatable{
..........
public function findForPassport($identifier,$parent) {
$a = $this
->Join('role as r', 'r.user_id', '=', 'users.id')
->get();
return $a->where('name', $identifier)->where('role_id',$parent)->first();
}
}
来自the link to passport issue #81 pointed by @Arun in OP:
There's probably a better way of doing this now but I extended the PassportServiceProvider and copied the registerAuthorizationServer function so that I could register my own grant type.
Swap out the provider in config\app.php with your new one:
'providers' => [
//Laravel\Passport\PassportServiceProvider::class,
App\Providers\PassportClientCredentialsServiceProvider::class,
Updated registerAuthorizationServer function that includes new grant option:
protected function registerAuthorizationServer()
{
parent::registerAuthorizationServer();
$this->app->singleton(AuthorizationServer::class, function () {
return tap($this->makeAuthorizationServer(), function ($server) {
/**
* @var $server AuthorizationServer
*/
$server->enableGrantType(
new ClientCredentialsGrant(), Passport::tokensExpireIn()
);
/** custom grant type */
$server->enableGrantType(
new PasswordOverrideGrant(
$this->app->make(UserRepository::class),
$this->app->make(RefreshTokenRepository::class)
), Passport::tokensExpireIn()
);
$server->enableGrantType(
$this->makeAuthCodeGrant(), Passport::tokensExpireIn()
);
$server->enableGrantType(
$this->makeRefreshTokenGrant(), Passport::tokensExpireIn()
);
$server->enableGrantType(
$this->makePasswordGrant(), Passport::tokensExpireIn()
);
$server->enableGrantType(
new PersonalAccessGrant(), new \DateInterval('P1Y')
);
});
});
}
PasswordOverrideGrant looks like this:
<?php
namespace App\Auth;
use App\User;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Grant\PasswordGrant;
use League\OAuth2\Server\RequestEvent;
use Psr\Http\Message\ServerRequestInterface;
class PasswordOverrideGrant extends PasswordGrant
{
protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)
{
$username = $this->getRequestParameter('username', $request);
if (is_null($username)) {
throw OAuthServerException::invalidRequest('username');
}
$custom_hash_token = $this->getRequestParameter('hash_token', $request);
if (is_null($custom_hash_token)) {
throw OAuthServerException::invalidRequest('identifier');
}
$credentials = [
'username' => $username,
'hash_token' => $custom_hash_token,
];
$user = User::where($credentials)->first();
if ($user instanceof User === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidCredentials();
}
return $user;
}
public function getIdentifier()
{
return 'password_override';
}
}
是否可以向 findForPassport 添加或再传递 1 个变量?
默认 laravel 护照登录,我只能传递 2 个变量(用户名、密码),但我想再传递 1 个变量并在 findForPassport 中检查该用户是否属于其他 table还是不是。
希望这个回答能对其他人有所帮助。
如果要添加变量并将此变量传递给 User Authenticate 模型中的 findPassport 函数,则需要更新 passport 中的 3 class :
- UserRepositoryInterface 在 vendor\league\oauth2-server\src\Repositories\UserRepositoryInterface
- PasswordGrant 在 vendor\league\oauth2-server\src\Grant\PasswordGrant
- UserRepository 在 vendor\laravel\passport\src\Bridge\UserRepository
在示例代码中,我将添加父变量,代码将如下所示
+在 UserRepositoryInterface class
interface UserRepositoryInterface extends RepositoryInterface
{
/**
* Get a user entity.
*
* @param string $username
* @param string $password
* @param string $grantType The grant type used
* @param ClientEntityInterface $clientEntity
*
* @return UserEntityInterface
*/
public function getUserEntityByUserCredentials(
$username,
$password,
$parent, <------variable example
$grantType,
ClientEntityInterface $clientEntity
);
}
+在 PasswordGrant class
class PasswordGrant extends AbstractGrant{
protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)
{
$username = $this->getRequestParameter('username', $request);
if (is_null($username)) {
throw OAuthServerException::invalidRequest('username');
}
$password = $this->getRequestParameter('password', $request);
if (is_null($password)) {
throw OAuthServerException::invalidRequest('password');
}
/**
* Get a user parent.
* varaible example
*/
$parent = $this->getRequestParameter('parent', $request);
if (is_null($parent)) {
throw OAuthServerException::invalidRequest('password');
}
$user = $this->userRepository->getUserEntityByUserCredentials(
$username,
$password,
$parent, <--- variable example get from request
$this->getIdentifier(),
$client
);
if ($user instanceof UserEntityInterface === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidCredentials();
}
return $user;
} }
+在 UserRepository class
class UserRepository implements UserRepositoryInterface
{
public function getUserEntityByUserCredentials($username, $password, $parent, $grantType, ClientEntityInterface $clientEntity)
/*add 1more parameter that implement from UserRepositoryInterface*/
{
$provider = config('auth.guards.api.provider');
if (is_null($model = config('auth.providers.'.$provider.'.model'))) {
throw new RuntimeException('Unable to determine authentication model from configuration.');
}
if (method_exists($model, 'findForPassport')) {
$user = (new $model)->findForPassport($username,$parent); <--- finally we pass parent variable to findForPassport here
} 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->getAuthPassword())) {
return;
}
return new User($user->getAuthIdentifier());
}
}
然后您可以从 findForPassport 中的参数中获取 $parent 值。但请确保您的 return 值为 eloquent 用户。如果您想加入 table,您可以查看我的下面的示例代码
class User extends Authenticatable{
..........
public function findForPassport($identifier,$parent) {
$a = $this
->Join('role as r', 'r.user_id', '=', 'users.id')
->get();
return $a->where('name', $identifier)->where('role_id',$parent)->first();
}
}
来自the link to passport issue #81 pointed by @Arun in OP:
There's probably a better way of doing this now but I extended the PassportServiceProvider and copied the registerAuthorizationServer function so that I could register my own grant type.
Swap out the provider in config\app.php with your new one:
'providers' => [ //Laravel\Passport\PassportServiceProvider::class, App\Providers\PassportClientCredentialsServiceProvider::class,
Updated registerAuthorizationServer function that includes new grant option:
protected function registerAuthorizationServer() { parent::registerAuthorizationServer(); $this->app->singleton(AuthorizationServer::class, function () { return tap($this->makeAuthorizationServer(), function ($server) { /** * @var $server AuthorizationServer */ $server->enableGrantType( new ClientCredentialsGrant(), Passport::tokensExpireIn() ); /** custom grant type */ $server->enableGrantType( new PasswordOverrideGrant( $this->app->make(UserRepository::class), $this->app->make(RefreshTokenRepository::class) ), Passport::tokensExpireIn() ); $server->enableGrantType( $this->makeAuthCodeGrant(), Passport::tokensExpireIn() ); $server->enableGrantType( $this->makeRefreshTokenGrant(), Passport::tokensExpireIn() ); $server->enableGrantType( $this->makePasswordGrant(), Passport::tokensExpireIn() ); $server->enableGrantType( new PersonalAccessGrant(), new \DateInterval('P1Y') ); }); }); }
PasswordOverrideGrant looks like this:
<?php namespace App\Auth; use App\User; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\RequestEvent; use Psr\Http\Message\ServerRequestInterface; class PasswordOverrideGrant extends PasswordGrant { protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client) { $username = $this->getRequestParameter('username', $request); if (is_null($username)) { throw OAuthServerException::invalidRequest('username'); } $custom_hash_token = $this->getRequestParameter('hash_token', $request); if (is_null($custom_hash_token)) { throw OAuthServerException::invalidRequest('identifier'); } $credentials = [ 'username' => $username, 'hash_token' => $custom_hash_token, ]; $user = User::where($credentials)->first(); if ($user instanceof User === false) { $this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request)); throw OAuthServerException::invalidCredentials(); } return $user; } public function getIdentifier() { return 'password_override'; } }