LoginSignup
11
10

More than 3 years have passed since last update.

Laravelで画面上でログインしているときだけ叩けるAPIを実装し、Postmanによる動作確認を行う

Last updated at Posted at 2020-12-24

概要

LaravelのAPIを実装し、次のようなことを調査・実装し、Postmanのあまりの便利さに感動したのでまとめる。
これがベスト、ではなくこう実装した、という記録。

  • ログイン中のユーザだけが利用できるようにする方法。
    • 実装したAPIのうち、ユーザ情報を返すAPIがあるため。未ログインのユーザには見せたくない。
    • APIは、モーダル上に情報を表示したり、取得した情報をセレクトボックスの選択肢として表示するのに使われる。
  • APIの動作確認のため、PostmanでCookie付きでリクエストする方法。
    • ログインしていれば200レスポンスが返ること、ログアウト状態なら情報が取得できないことを確かめたい。
  • (おまけ)実際にjsでajax通信する際は、どのように認証させればいいのか。

動作確認環境

Laravel 6.20.2
PHP 7.4

ログイン中のユーザだけが利用できるように、セッションIDで認証する

今回の開発においてはAPIトークンやLaravel Passportを使った実装を行う予定がないため、Laravelのデフォルトで用意されているapiミドルウェアグループの定義を書き換える。

ミドルウェアの追加

Laravelのデフォルトのままでは route/api.phpに記述されたルーティングにはCookieとセッションによる認証に関するミドルウェアが設定されていない。
APIに対してCookieとセッションによる認証を有効化するため、Kernel.phpにミドルウェアを4点追加する。

app/Http/Kernel.php

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
        ★★★ここから★★★
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        ★★★ここまで★★★
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

APIのルーティングをauthミドルウェアを利用するように修正する

route/api.phpには、デフォルトだと次のようにただログイン中ユーザの情報を返すAPIが記述されている。
ここではauth:apiというように、api guardが利用されている。

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

これを、authに書き換える。

Route::middleware('auth')->group(function () {
    // ルーティングも実装したAPIに書き換える
    Route::get('/users', xxxxxx);
});

他、試したこと

当初、config/auth.phpのapi guardの部分を、

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

下記のように、 auth.phpで定義したguardをroute/api.phpでミドルウェアに設定すればいいと思ったが、そうしても認証できなかった。

(SessionDriverが生成されること、Illuminate\Auth\GuardHelper の
authenticate()で$this->user()が空になっていることまでは突き止めた。なのでキャッシュが残っていることが原因ではない。
src/Illuminate/Auth/SessionGuard.phpのuser()のなかでユーザが取得できていないっぽい。でも、driverとproviderを同じものにしているのにミドルウェアをauth:apiauthにすると認証できる理由がわからない・・・。)

        'api' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

結局、config/auth.phpは書き換えず、ミドルウェアをauth:apiからauthに書き換えることにした。

何か分かれば追記する。

参考

PostmanでCookie付きでリクエストする

ログインしているユーザのみ利用できるように、Cookieとセッションを使った認証を行うようにしたため、PostmanでAPIの動作確認をするには、Cookie付きでリクエストする必要がある。

以下の手順で設定を行う。

  • Google拡張機能 Postman Interceptor をインストールする。

  • 「Capture Cookies」をONにし、動作確認をしたい環境のドメインを追加する。
    localの場合は localhost で、ポート番号は不要。
    image.png

  • Postman側でも、Interceptor Bridgeをインストールする。
    (Capture requests and cookies with Postmanのアイコンから。初回のみ)

  • 「Capture Cookies」をONにし、動作確認をしたい環境のドメインを追加する。
    localの場合は localhost で、ポート番号は不要。
    image.png

  • 以上の手順でクッキーがキャプチャーされている状態になる。
    ブラウザでlocalhostにアクセスし、Postman側でCookies(下記画像参照)にクッキーが含まれていることを確認する。 (手動で書き換えることも可能と思われるが、勝手にcaptureしてくれるので使う場面がなかった。)
    image.png

画面上でログインした状態でAPIを正常なリクエストすると200レスポンスが返り、ログアウト状態でリクエストすると 401 Unauthorize が返ることを確認できればOK。
ログインしているはずなのに401が返ってくる、というときは、Cookieをcaptureできているかどうか確認すること。

参考

その他注意事項

ブラウザ側のInterceptorとPostmanがDISCONNECT状態になることがあったが、ブラウザまたはPostmanを再起動すれば正常に接続できた。

おまけ Postmanでパスパラメータを指定したい場合

今更わかるPostman〜便利なAPI開発補助ツール〜より

pathパラメータはURL中に:param_nameで設定

することで、 Query Params の下に Path Variables が出現します。なんだこの隠しコマンドみたいな技・・・。
image.png

(参考)ajax通信する際、同一ドメインに対してはCookieを送信するようになっている

実装したAPIを画面側で呼び出す際は、Cookie情報は一切触れていない。
なぜなら、呼び出す側と呼び出すAPIが同一ドメインである場合、Cookieは勝手に送信されるようになっているから。

ajaxで呼び出す際の実際のコードはこんな感じ。
ログインさえしていれば、呼び出すことができる。

    $.ajax({
        url: '/api/xxxxx/',
        type: 'GET',
        contentType: 'application/json; charset=UTF-8',
        data: {
            // 「type: 'GET'」と指定しているので、自動でGETパラメータとして扱われる
        }
    }).then((res) => {
        // モーダルに表示したり、セレクトボックスの選択肢として追加したり、etc...
    });

参考

  • jqueryの.ajax()メソッドがセッションCookieを送信しないのはなぜですか?

    • このサイトを参考にしたが、あまり信憑性がないので参考まで。
    • 『Webを支える技術』『安全なWebアプリケーションの作り方』も確認したが、『Webを支える技術』には明確な記述はなかった。 『安全なWebアプリケーションの作り方』p.65 に、

    いったんクッキー値を覚えたブラウザは、
    その後同じサイト(example.jp)にリクエストを送信する際には、覚えたクッキー値(PHPSESSID=・・・)を送信します。

    と記載があった。
    javascriptでリクエストしようがPHPでリクエストしようが対象が同一ドメインなら、ブラウザはCookieを送信するようになっている、と捉えることにした。

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10