Laravelのステージング環境へBasic認証をかける方法|サンプルコード付き

/ 更新:

ステージング環境は「開発途中の機能を関係者だけで確認したい」「検索エンジンに拾われたくない」「外部にURLが漏れたときの被害を抑えたい」といった理由で、アクセス制限を入れるケースが多いです。

その中でも Basic認証は、

  • ブラウザだけで完結(追加UI不要)
  • 実装コストが低い
  • とりあえずの“門番”として十分機能する

という理由で、ステージング用途では定番です。

この記事では、Laravel側で APP_ENV=staging のときだけ Basic認証を要求し、それ以外(local / production 等)では素通しにする実装を紹介します。

方式の選択肢:Laravelでかける?Webサーバでかける?

ステージングにBasic認証をかける方法は大きく2つです。

A. Laravel(アプリ)側でかける(本記事のメイン)

メリット

  • 環境判定(stagingのみ)をコードで完結できる
  • ルート単位で適用範囲を変えやすい(管理画面だけ、特定ツールだけ、など)
  • インフラ変更なしで導入可能(PaaSでもやりやすい)

デメリット

  • Laravelまでリクエストが到達する(=アプリの前段では止まらない)
  • 静的ファイル配信(画像等)には効かない構成もある(配信経路次第)

B. Webサーバ(Nginx/Apache)側でかける

メリット

  • Laravelに到達する前に遮断できる(負荷・攻撃耐性の観点で強い)
  • 静的ファイルも含めて一律で守りやすい

デメリット

  • 環境ごとにサーバ設定が必要(ホスティング形態によっては触れない)
  • “ルート単位の柔軟さ”は落ちる(設定で頑張る必要がある)

結論として、「stagingだけ」「早く入れたい」「運用もしやすくしたい」なら Laravelミドルウェア方式が第一候補になります。


実装手順(Laravelミドルウェア方式)

1) Middleware を作成

app/Http/Middleware/StagingBasicAuth.php を作成します(php artisan make:middleware StagingBasicAuth でもOK)。

ポイントは以下です。

  • staging 以外は next() で素通し
  • ID/PW は 環境変数(.env で管理
  • hash_equals で比較(タイミング攻撃対策)
  • stagingなのにID/PW未設定なら 500で落として“設定漏れに気付ける” ようにする(運用向け)
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class StagingBasicAuth
{
    public function handle(Request $request, Closure $next): Response
    {
        // staging 以外は無効(素通し)
        if (!app()->environment('staging')) {
            return $next($request);
        }

        $user = (string) env('BASIC_AUTH_USER', '');
        $pass = (string) env('BASIC_AUTH_PASS', '');

        // staging なのに設定が空なら事故るので 500 にして気付けるようにする(運用向け)
        if ($user === '' || $pass === '') {
            abort(500, 'BASIC_AUTH_USER / BASIC_AUTH_PASS is not set for staging.');
        }

        $givenUser = (string) $request->getUser();
        $givenPass = (string) $request->getPassword();

        // timing attack 対策:hash_equals
        if (!hash_equals($user, $givenUser) || !hash_equals($pass, $givenPass)) {
            return response('Unauthorized', 401, [
                'WWW-Authenticate' => 'Basic realm="Staging"',
            ]);
        }

        return $next($request);
    }
}

2) bootstrap/app.php に middleware を登録

Laravel 11以降は、ミドルウェア周りの設定が bootstrap/app.php に集約されています(withMiddleware)。
グローバルに適用したい場合は append() で追加します。

use App\Http\Middleware\StagingBasicAuth;

->withMiddleware(function (Middleware $middleware): void {
// ーバルミドルウェア(全HTTPリクエストに適用)
$middleware->append(StagingBasicAuth::class);
}

3) .env に認証情報を追加(stagingのみ)

APP_ENV=staging

BASIC_AUTH_USER=your_user
BASIC_AUTH_PASS=your_password

運用の注意

  • パスワードは推測されにくい長さにする(最低でもランダム16文字程度)
  • 共有範囲が広いなら、定期ローテーション前提にする
  • 認証情報をGit管理しない(.env をコミットしない)

「全ページ」ではなく「特定ルートだけ」にかけたい場合

テージングでも、例えば以下は“素通しにしたい”ことがあります。

  • ヘルスチェックURL(ロードバランサ等)
  • Webhook受信エンドポイント
  • 特定の検証URLだけ関係者に公開したい

その場合は グローバル適用ではなく、ルート/グループにだけ適用にすると運用が楽です。

例:ルートミドルウェアとして alias 登録して使う

bootstrap/app.php でエイリアス登録(例)

->withMiddleware(function (Middleware $middleware): void {
    $middleware->alias([
        'staging.basic' => \App\Http\Middleware\StagingBasicAuth::class,
    ]);
})

ルート側

Route::middleware(['staging.basic'])->group(function () {
    Route::get('/admin', fn () => 'admin');
    Route::get('/tools', fn () => 'tools');
});

こうすると「必要な範囲だけ守る」構成にできます。

About Shinya Okada

1989年生まれ。既婚。東京高専・茨城大。
グループ会社SE→社内SEへ転職。
趣味:バレーボール、投資、プログラミング