Laravel Passportのルーティングをカスタマイズする

LaravelにPassportという標準ライブラリを導入することでOAuth認証を実装することが出来ますが、そのままではエンドポイントが標準のままなのでセキュリティ的にどうなんだろう…。

ということで今回はこれをカスタマイズしていきます。

ラッパークラスの作成

今回パスワード認証、すなわちPassword Grantなアクセストークンのみ利用することを想定します。

公式ドキュメントにもあるとおり、Password Grantなアクセストークンを取得するEndpointは`/oauth/token`です。例としてコレをapi/v1/auth/accessTokenに修正してみましょう。

Passportライブラリ本体は`\Laravel\Passport\Passport`です。まずはこれを継承する独自のラッパークラスを作成します。今回名前空間(namespace)がぐちゃぐちゃになるのも嫌だったので~/TeensTown/Passport/Passport.phpを作成しました。

独自実装の名前空間を追加する際はcomposer.jsonによる設定が必要です。

    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "TeensTown\\": "TeensTown/"  <- ここと
        },
        "classmap": [
            "database/seeds",
            "database/factories",
            "TeensTown"  <- ここ
        ]
    },

上記のような追加設定を行いましょう。

次に、独自拡張のPassport.phpでroutesメソッドをoverrideします。

public static function routes($callback = null, array $options = [])
{
    $callback = $callback ?: function ($router) {
        $router->all();
    };

    $defaultOptions = [
        'prefix' => 'auth',
        'namespace' => '\Laravel\Passport\Http\Controllers',
    ];

    $options = array_merge($defaultOptions, $options);

    Route::group($options, function ($router) use ($callback) {
        $callback(new RouteRegistrar($router));
    });
}

続いて`\Laravel\Passport\RouteRegistrar`を継承する~/TeensTown/Passport/RouteRegistrar.phpを作成します。

<?php

namespace TeensTown\Passport;

use Illuminate\Contracts\Routing\Registrar as Router;

class RouteRegistrar extends \Laravel\Passport\RouteRegistrar
{
    /**
     * The router implementation.
     *
     * @var \Illuminate\Contracts\Routing\Registrar
     */
    protected $router;

    /**
     * Create a new route registrar instance.
     *
     * @param  \Illuminate\Contracts\Routing\Registrar  $router
     * @return void
     */
    public function __construct(Router $router)
    {
        $this->router = $router;
    }

    /**
     * Register routes for transient tokens, clients, and personal access tokens.
     *
     * @return void
     */
    public function all()
    {
        // $this->forAuthorization();
        $this->forAccessTokens();
        // $this->forTransientTokens();
        // $this->forClients();
        // $this->forPersonalAccessTokens();
    }

    /**
     * Register the routes needed for authorization.
     *
     * @return void
     */
    public function forAuthorization()
    {
        // $this->router->group(['middleware' => ['web', 'auth']], function ($router) {
        //     $router->get('/authorize', [
        //         'uses' => 'AuthorizationController@authorize',
        //         'as' => 'passport.authorizations.authorize',
        //     ]);

        //     $router->post('/authorize', [
        //         'uses' => 'ApproveAuthorizationController@approve',
        //         'as' => 'passport.authorizations.approve',
        //     ]);

        //     $router->delete('/authorize', [
        //         'uses' => 'DenyAuthorizationController@deny',
        //         'as' => 'passport.authorizations.deny',
        //     ]);
        // });
    }

    /**
     * Register the routes for retrieving and issuing access tokens.
     *
     * @return void
     */
    public function forAccessTokens()
    {
        $this->router->post('/accessToken', [
            'uses' => 'AccessTokenController@issueToken',
            'as' => 'passport.token',
            'middleware' => 'throttle',
        ]);

        $this->router->group(['middleware' => ['auth']], function ($router) {
            // $router->get('/tokens', [
            //     'uses' => 'AuthorizedAccessTokenController@forUser',
            //     'as' => 'passport.tokens.index',
            // ]);

            $router->delete('/revoke/{token_id}', [
                'uses' => 'AuthorizedAccessTokenController@destroy',
                'as' => 'passport.tokens.destroy',
            ]);
        });
    }

    /**
     * Register the routes needed for refreshing transient tokens.
     *
     * @return void
     */
    public function forTransientTokens()
    {
        // $this->router->post('/token/refresh', [
        //     'middleware' => ['web', 'auth'],
        //     'uses' => 'TransientTokenController@refresh',
        //     'as' => 'passport.token.refresh',
        // ]);
    }

    /**
     * Register the routes needed for managing clients.
     *
     * @return void
     */
    public function forClients()
    {
        // $this->router->group(['middleware' => ['web', 'auth']], function ($router) {
        //     $router->get('/clients', [
        //         'uses' => 'ClientController@forUser',
        //         'as' => 'passport.clients.index',
        //     ]);

        //     $router->post('/clients', [
        //         'uses' => 'ClientController@store',
        //         'as' => 'passport.clients.store',
        //     ]);

        //     $router->put('/clients/{client_id}', [
        //         'uses' => 'ClientController@update',
        //         'as' => 'passport.clients.update',
        //     ]);

        //     $router->delete('/clients/{client_id}', [
        //         'uses' => 'ClientController@destroy',
        //         'as' => 'passport.clients.destroy',
        //     ]);
        // });
    }

    /**
     * Register the routes needed for managing personal access tokens.
     *
     * @return void
     */
    public function forPersonalAccessTokens()
    {
        // $this->router->group(['middleware' => ['web', 'auth']], function ($router) {
        //     $router->get('/scopes', [
        //         'uses' => 'ScopeController@all',
        //         'as' => 'passport.scopes.index',
        //     ]);

        //     $router->get('/personal-access-tokens', [
        //         'uses' => 'PersonalAccessTokenController@forUser',
        //         'as' => 'passport.personal.tokens.index',
        //     ]);

        //     $router->post('/personal-access-tokens', [
        //         'uses' => 'PersonalAccessTokenController@store',
        //         'as' => 'passport.personal.tokens.store',
        //     ]);

        //     $router->delete('/personal-access-tokens/{token_id}', [
        //         'uses' => 'PersonalAccessTokenController@destroy',
        //         'as' => 'passport.personal.tokens.destroy',
        //     ]);
        // });
    }
}

今回はAccess Tokenのみの想定なので`forAccessTokens`メソッドだけ利用していますが、必要に応じて書き換えてください。

ルーティングの修正

routes/api.phpに、今回実装したPassport.phpによるルーティングを適用します。

use TeensTown\Passport\Passport;

Route::group(['prefix' => '/v1'], function () {
    Passport::routes();
});

技術ブログでおまじないのように書かれる`Passport::routes();`ですが、もちろん通常のルーティングのようにPrefixやMiddlewareも実装できます。独自のラッパークラスをuseするのを忘れずに

タイトルとURLをコピーしました