Laravelのpassportで既存のgrantをカスタマイズ、追加する必要があったので、手順をメモ
※ 各種追加しているファイルのディレクトリは自信がないので指摘ください
カスタムGrant追加
AbstractGrantを実装したクラスを作成
respondToAccessTokenRequestメソッドを独自に実装する必要がある
中身はPasswordGrantをコピーしてgetIdentifierのみ変更している
app/Providers/OAuth2/Server/Grant/CustomGrant.php
<?php
namespace App\Providers\OAuth2\Server\Grant;
use League\OAuth2\Server\Grant\AbstractGrant;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\UserEntityInterface;
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
use League\OAuth2\Server\RequestEvent;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use Psr\Http\Message\ServerRequestInterface;
class CustomGrant extends AbstractGrant {
/**
* @param UserRepositoryInterface $userRepository
* @param RefreshTokenRepositoryInterface $refreshTokenRepository
*/
public function __construct(
UserRepositoryInterface $userRepository,
RefreshTokenRepositoryInterface $refreshTokenRepository
) {
$this->setUserRepository($userRepository);
$this->setRefreshTokenRepository($refreshTokenRepository);
$this->refreshTokenTTL = new \DateInterval('P1M');
}
/**
* {@inheritdoc}
*/
public function respondToAccessTokenRequest(
ServerRequestInterface $request,
ResponseTypeInterface $responseType,
\DateInterval $accessTokenTTL
) {
// Validate request
$client = $this->validateClient($request);
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
$user = $this->validateUser($request, $client);
// Finalize the requested scopes
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
// Issue and persist new tokens
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes);
$refreshToken = $this->issueRefreshToken($accessToken);
// Inject tokens into response
$responseType->setAccessToken($accessToken);
$responseType->setRefreshToken($refreshToken);
return $responseType;
}
/**
* @param ServerRequestInterface $request
* @param ClientEntityInterface $client
*
* @throws OAuthServerException
*
* @return UserEntityInterface
*/
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');
}
$user = $this->userRepository->getUserEntityByUserCredentials(
$username,
$password,
$this->getIdentifier(),
$client
);
if ($user instanceof UserEntityInterface === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidCredentials();
}
return $user;
}
/**
* {@inheritdoc}
*/
public function getIdentifier()
{
// POSTのgrant_typeで指定する名称になる
return 'custom';
}
}
PassportServiceProvider拡張
PassportServiceProviderを継承してカスタムPassportServiceProviderを作成
registerAuthorizationServerメソッドをオーバーライドし、作成したカスタムGrantの呼び出しを追加する
app/Providers/CustomPassportServiceProvider.php
<?php
namespace App\Providers;
use DateInterval;
use Laravel\Passport\Passport;
use Laravel\Passport\PassportServiceProvider;
use League\OAuth2\Server\AuthorizationServer;
use Laravel\Passport\Bridge\PersonalAccessGrant;
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
use App\Providers\OAuth2\Server\Grant\CustomGrant;
class CustomPassportServiceProvider extends PassportServiceProvider
{
/**
* Register the authorization server.
*
* @return void
*/
protected function registerAuthorizationServer()
{
$this->app->singleton(AuthorizationServer::class, function () {
return tap($this->makeAuthorizationServer(), function ($server) {
$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')
);
// 追加したカスタムGrantの呼び出し
$server->enableGrantType(
$this->makeCustomGrant(), Passport::tokensExpireIn()
);
$server->enableGrantType(
new ClientCredentialsGrant, Passport::tokensExpireIn()
);
if (Passport::$implicitGrantEnabled) {
$server->enableGrantType(
$this->makeImplicitGrant(), Passport::tokensExpireIn()
);
}
});
});
}
/**
* Create and configure a Password grant instance.
*
* @return \App\Providers\OAuth2\Server\Grant\CustomGrant
*/
protected function makeCustomGrant()
{
$grant = new CustomGrant(
$this->app->make(\Laravel\Passport\Bridge\UserRepository::class),
$this->app->make(\Laravel\Passport\Bridge\RefreshTokenRepository::class)
);
$grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
return $grant;
}
}
登録するサービスプロバイダーの変更
PassportServiceProviderを継承して作成したCustomPassportServiceを登録する
config/app.php
/* Package Service Providers... */
Laravel\Tinker\TinkerServiceProvider::class,
Laravel\Tinker\TinkerServiceProvider::class,
//Laravel\Passport\PassportServiceProvider::class,
App\Providers\CustomPassportServiceProvider::class,
OAuthトークン取得
上記を実装することでカスタムGrantでOAuthのトークンを取得できる
アクセスURL
http://ドメイン/oauth/token
POSTパラメータ
{
"client_id": "XX",
"client_secret": "XXXXXXXXXXXXXXXXXXXXXXX",
"username": "XXXXXXXXXXXXXXXXXXXXXXX",
"password": "XXXXXXXXXXXXXXXXXXXXXXX",
"grant_type": "custom",
"scope": ""
}
もっとこうした方がいい、ここ間違ってる等あれば指摘お願いします。