【PHP Laravel】Laravel 5.4 依照不同環境提升至 SSL https

動機


因為已經把開發環境docker化了,但是由於AWS上面的憑證是使用 ACM
也就是AWS的免費憑證做為開發,內部還是使用http 80作為傳輸手段
這部分攸關於AWS的網站架構設計,有機會再拿出來寫

總之結論就是,希望在開發的時候走80(http),而上線的時候自動變為443 (https)


過程


本來使蠢蠢的讓每個頁面都提升至https,但是這樣會導致開發環境也被升到https
443沒有服務,所以直接死亡
Laravel是一個很成熟的framework,已經內建處理這種情況的函式了

首先建立一個Middleware,方便所有環境共用

app/Http/Middleware/SslMiddleware.php

<?php
namespace App\Http\Middleware;
use Closure;
class SslMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
          if(in_array(env('APP_ENV'),json_decode(env('SSL_UPGRADE_ENV'),true))){
            \URL::forceScheme('https');
          }
          return $next($request);
    }
}
這邊的 \URL::forceScheme('https'); 就是重點了
(PS 如果是5.3版以前的,叫做\URL::forceSchema('https');,最後一個字是a,合理懷疑官方升版的時候打錯字了XDDDDDDDDDDDD)

整段的大意是,要是發現 APP_ENV 的環境是在 SSL_UPGRADE_ENV 的陣列內,那麼就提升
在這之前請在.env內部加上 SSL_UPGRADE_ENV
我這邊是這樣設定的

APP_ENV=lab
SSL_UPGRADE_ENV=["lab","staging","production"]
接著告訴laravel在什麼情況下要使用這個middleware
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,
            \App\Http\Middleware\SslMiddleware::class,
        ],
        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

注意 \App\Http\Middleware\SslMiddleware::class 這句是新加的
代表在使用web middleware的時候,自動提升成ssl
如果想知道route有什麼會經過這個middleware,可以看RouteServiceProvider.php
app/Providers/RouteServiceProvider.php


 protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
        Route::prefix('dashboard')
            ->middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/dashboard.php'));
這邊會告訴你哪個路由跑哪邊,就可以很快速的整理出哪些需要走ssl了

留言