Laravel 5-HTTPSへのリダイレクト


126

私の最初のLaravel 5プロジェクトに取り組んでいますが、アプリにHTTPSを強制するロジックをどこにどのように配置するかわかりません。ここで重要なのは、アプリを指すドメインが多く、3つのうち2つだけがSSLを使用していることです(3つ目はフォールバックドメイン、長い話)。したがって、これを.htaccessではなく、アプリのロジックで処理したいと考えています。

Laravel 4.2では、次の場所にあるこのコードでリダイレクトを実行しましたfilters.php

App::before(function($request)
{
    if( ! Request::secure())
    {
        return Redirect::secure(Request::path());
    }
});

私はミドルウェアがこのようなものを実装すべき場所だと思っていますが、それを使用してこれを完全に理解することはできません。

ありがとう!

更新

私のようにCloudflareを使用している場合は、コントロールパネルに新しいページルールを追加することでこれを実現できます。


では、3番目のドメインはどうなりますか?すべてのルートでhttpsを強制すると、3番目のドメインは引き続き機能しますか?
ローレンス、

それを検出する$_SERVER['HTTP_HOST']
NightMICU 2015

cloudflareページルールが有効になるまでにかかった時間
CodeGuru

ああ、私はDNS設定でプロキシをオンにしなければなりませんでした!
CodeGuru

回答:


252

ミドルウェアクラスで動作させることができます。考えさせてください。

namespace MyApp\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\App;

class HttpsProtocol {

    public function handle($request, Closure $next)
    {
            if (!$request->secure() && App::environment() === 'production') {
                return redirect()->secure($request->getRequestUri());
            }

            return $next($request); 
    }
}

次に、このミドルウェアをすべてのリクエストに適用しKernel.php、次のようにルールをファイルに設定します。

protected $middleware = [
    'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
    'Illuminate\Cookie\Middleware\EncryptCookies',
    'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
    'Illuminate\Session\Middleware\StartSession',
    'Illuminate\View\Middleware\ShareErrorsFromSession',

    // appending custom middleware 
    'MyApp\Http\Middleware\HttpsProtocol'       

];

上記のサンプルでは、​​ミドルウェアは次の場合にすべてのリクエストをhttpsにリダイレクトします。

  1. 現在のリクエストには安全なプロトコルがありません(http)
  2. 環境がに等しい場合production。だから、あなたの好みに応じて設定を調整してください。

クラウドフレア

WildCard SSLを使用した本番環境でこのコードを使用していますが、コードは正しく機能します。&& App::environment() === 'production'localhostで削除してテストすると、リダイレクトも機能します。そのため、SSLがインストールされているかどうかは問題ではありません。Httpsプロトコルにリダイレクトするには、Cloudflareレイヤーに非常に注意を払う必要があるようです。

2015年3月23日編集

@Adam Linkの提案に感謝します:Cloudflareが通過しているヘッダーが原因である可能性があります。CloudFlareはおそらくHTTP経由でサーバーにヒットし、HTTPSリクエストを転送していることを宣言するX-Forwarded-Protoヘッダーを渡します。ミドルウェアに別の行を追加する必要があります...

$request->setTrustedProxies( [ $request->getClientIp() ] ); 

... CloudFlareが送信するヘッダーを信頼する。これはリダイレクトループを停止します

2016年9月27日編集-Laravel v5.3

ミドルウェアクラスをwebグループに追加するだけですkernel.php file

protected $middlewareGroups = [
    'web' => [
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,

        // here
        \MyApp\Http\Middleware\HttpsProtocol::class

    ],
];

覚えているwebグループは、あなたが設定する必要はありませんので、デフォルトではすべてのルートに適用されるweb路線もコントローラーで明示的に。

2018年8月23日編集-Laravel v5.7

  • 使用できる環境に応じてリクエストをリダイレクトしますApp::environment() === 'production'。以前のバージョンはでした env('APP_ENV') === 'production'
  • \URL::forceScheme('https');実際に使用してもリダイレクトされません。https://Webサイトが表示されたときにリンクを作成するだけです。

5
これは私にリダイレクトループを与えているようです...しかしそれはうまくいくはずです 違いがあるかどうかはわかりませんが、Cloudflare SSLを使用しています。しかし、それが単純なリダイレクトを変えるとは思いません。
NightMICU 2015

3
@NightMICUリダイレクトの問題を解決したかどうかはわかりませんが、Cloudflareが渡すヘッダーが原因である可能性があります。CloudFlareはおそらくHTTP経由でサーバーにヒットし、HTTPSリクエストを転送していることを宣言するX-Forwarded-Protoヘッダーを渡します。ミドルウェアに、$request->setTrustedProxies( [ $request->getClientIp() ] );CloudFlareが送信するヘッダーを信頼するように言う別の行を追加する必要があります。これにより、リダイレクトループが停止します。
Adam Link

2
@manixすごい。今週末、私自身のプロジェクトでこのHTTPSの問題を経験しました-その小さなものは何時間もあなたを苛立たせます!
Adam Link

8
正解です。詳細の1つ:永続的な動きであることをGoogleに示すには、301リダイレクトを使用することをお勧めします。Like:return redirect()->secure($request->getRequestUri(), 301);
adriaroca

4
ロードバランサーまたはプロキシーの下にいる人は、secure()に変更して、$request->server('HTTP_X_FORWARDED_PROTO') != 'https'これでうまくいく
Shiro

63

AppServiceProviderで私にとってうまくいった他のオプションは、このコードをbootメソッドに配置します。

\URL::forceScheme('https');

forceSchema( 'https')の前に記述された関数が間違っていました、そのforceScheme


16
ねえ、ちょうど周りグーグルを通じてこれを見つけた-ノートを5.4に、それはだと\URL::forceScheme('https');
devの

5
同じファイルで、次のこともできますif($this->app->environment() === 'production'){ $this->app['request']->server->set('HTTPS', true); }
Rory

2
意味\URL::forceScheme('https')
ですか

17
これはリンクを構築するためだけのものであると確信しています。これはユーザーにhttpsを強制するものではなく、https://で始まるリンクのみを提供します
Weston Watson

うん、それは@WestonWatsonで起こった。見つかった場合は、ソリューションを親切に共有してください
Harat

33

または、Apacheを使用している場合は、.htaccessファイルを使用してURLにhttpsプレフィックスを使用するように強制できます。Laravel 5.4では、次の行を.htaccessファイルに追加しましたが、うまくいきました。

RewriteEngine On

RewriteCond %{HTTPS} !on
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

2
複数の環境(開発、ステージング、本番)がある場合、すべてにSSLを設定する必要があるため、これは適切ではありません。
Mladen Janjetovic 2017年

@MladenJanjetovic RewriteCond %{HTTP_HOST} !=localhostdevでこれを回避するために使用できます。
Dan

3
@ダン-はい、ただし、ステージ、ローカルに設定する必要があります(そして、開発者がローカル開発で.dev、.local、サブドメインなどの異なるURLを使用している場合、これはさらに複雑になります)。そのようなロジックをアプリケーションに入れたいと思います。
Mladen Janjetovic

16

laravel 5.4の場合、.htaccessの代わりにこの形式を使用してhttpsリダイレクトを取得します

namespace App\Providers;

use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        URL::forceScheme('https');
    }
}

15
明確にするために:1)これらの変更はapp / Providers / AppServiceProvider.phpで行う必要があります。2)これは、アプリ内で生成されたリンクをSSLを使用するように設定するだけであり、SSLの使用を強制するものではありません
フェニックス

こんにちは、次のルートに移動するボタンをクリックしても、この方法でルートが生成されません。エラー404
Saket Sinha

これはhttpsリダイレクトではありません。しかし、それはhttps://サイトの提供を可能にします。http://に変更すると、同様に機能します。
フラン

12

manixの回答に似ていますが、1つの場所にあります。HTTPSを強制するミドルウェア

namespace App\Http\Middleware;

use Closure;

use Illuminate\Http\Request;

class ForceHttps
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!app()->environment('local')) {
            // for Proxies
            Request::setTrustedProxies([$request->getClientIp()]);

            if (!$request->isSecure()) {
                return redirect()->secure($request->getRequestUri());
            }
        }

        return $next($request);
    }
}

リクエストは静的である必要がありますか?
GFxJamal

@jRheskおそらくそうではありませんが、答えを自由に変更してみてください
Mladen Janjetovic

8

これはLarave 5.2.x以降用です。一部のコンテンツをHTTPS経由で提供し、他のコンテンツをHTTP経由で提供するオプションが必要な場合は、ここで私に有効なソリューションを使用できます。なぜ誰かがHTTPS経由で一部のコンテンツのみを提供したいのでしょうか?HTTPSですべてを提供しないのはなぜですか?

HTTPS経由でサイト全体にサービスを提供することはまったく問題ありませんが、HTTPS経由ですべてを切断すると、サーバーで追加のオーバーヘッドが発生します。暗号化は安くはありません。わずかなオーバーヘッドもアプリの応答時間に影響を与えます。一般的なハードウェアは安価であり、影響は無視できると主張できますが、私は余談です:)マーケティングコンテンツの大きなページに画像などをhttps経由で提供するという考えは好きではありません。だからここに行く。これは、ミドルウェアを使用して上記で提案されているものと似ていますが、HTTP / HTTPS間を切り替えられる完全なソリューションです。

最初にミドルウェアを作成します。

php artisan make:middleware ForceSSL

これがミドルウェアの外観です。

<?php

namespace App\Http\Middleware;

use Closure;

class ForceSSL
{

    public function handle($request, Closure $next)
    {

        if (!$request->secure()) {
            return redirect()->secure($request->getRequestUri());
        }

        return $next($request);
    }
}

ローカル開発と本番環境の両方にHTTPSを設定しているため、必要がないため、環境に基づいてフィルタリングしないことに注意してください。

次のコードをrouteMiddleware \ App \ Http \ Kernel.phpに追加して、SSLを強制するルートグループを選択できるようにします。

    protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'forceSSL' => \App\Http\Middleware\ForceSSL::class,
];

次に、2つの基本的なグループのログイン/サインアップなど、Authミドルウェアの背後にあるすべてのものを保護したいと思います。

Route::group(array('middleware' => 'forceSSL'), function() {
/*user auth*/
Route::get('login', 'AuthController@showLogin');
Route::post('login', 'AuthController@doLogin');

// Password reset routes...
Route::get('password/reset/{token}', 'Auth\PasswordController@getReset');
Route::post('password/reset', 'Auth\PasswordController@postReset');

//other routes like signup etc

});


Route::group(['middleware' => ['auth','forceSSL']], function()
 {
Route::get('dashboard', function(){
    return view('app.dashboard');
});
Route::get('logout', 'AuthController@doLogout');

//other routes for your application
});

ミドルウェアがコンソールから適切にルートに適用されていることを確認します。

php artisan route:list

これで、アプリケーションのすべてのフォームまたは機密領域が保護されました。重要なのは、ビューテンプレートを使用して、安全なパブリック(https以外の)リンクを定義することです。

上記の例に基づいて、安全なリンクを次のようにレンダリングします-

<a href="{{secure_url('/login')}}">Login</a>
<a href="{{secure_url('/signup')}}">SignUp</a>

安全でないリンクは次のようにレンダリングできます

<a href="{{url('/aboutus',[],false)}}">About US</a></li>
<a href="{{url('/promotion',[],false)}}">Get the deal now!</a></li>

これにより、https:// yourhost / loginhttp:// yourhost / aboutusなどの完全修飾URLがレンダリングされます

完全修飾URLをhttpでレンダリングせず、相対リンクurl( '/ aboutus')を使用した場合、ユーザーが安全なサイトにアクセスした後、httpsが持続します。

お役に立てれば!


7

何についてちょうど使用して.htaccessの HTTPSリダイレクトを達成するためにファイルを?これは、(パブリックフォルダではなく)プロジェクトルートに配置する必要があります。サーバーは、プロジェクトのルートディレクトリを指すように構成する必要があります。

<IfModule mod_rewrite.c>
   RewriteEngine On
   # Force SSL
   RewriteCond %{HTTPS} !=on
   RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
   # Remove public folder form URL
   RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

私はこれをlaravel 5.4(この回答を書いている時点での最新バージョン)に使用しますが、laravelが変更または一部の機能を削除しても、機能バージョンでは引き続き機能するはずです。


Chromeでエラーが発生する:リダイレクトが多すぎます。このようにループしているようです
フェニックス2017年

こんにちは、私は答えを更新しました。この.htaccessをプロジェクトのルートディレクトリに置き、サーバー(apache構成)がプロジェクトのルートを指すようにしてください。
Maulik Gangani 2017年

1
@MladenJanjetovicこれらの環境では異なるhtaccessファイルを使用できます
Burgi

1
@MladenJanjetovicをアプリケーションで使用することには確かに利点がありますが、効率と速度の観点からは、リダイレクトのためだけにLaravelをロードする必要がないように、サーバー構成でこれを使用する方が有利だと思います。シングルバージョンの.htaccessの環境固有の構成は、次のような書き換え条件を使用してドメインをチェックすることで実現できますRewriteCond %{HTTP_HOST} productiondomain\.com$ [NC]
Chris

1
私もこれをルートディレクトリの.htaccessに配置することを好みます。Crhisが言ったように、環境固有の設定はここで実行できますが、Mladenのソリューションよりも少しエレガントではありません。
ジョバン

6

RewriteRuleを使用して、index.phpと同じフォルダーの.htaccessにsslを強制できます。
画像を添付して追加し、他のすべてのルールの前に追加してください ssl .htaccessの設定


3

IndexController.phpに

public function getIndex(Request $request)
{
    if ($request->server('HTTP_X_FORWARDED_PROTO') == 'http') {

        return redirect('/');
    }

    return view('index');
}

AppServiceProvider.phpに

public function boot()
{
    \URL::forceSchema('https');

}

AppServiceProvider.phpでは、すべてのリダイレクトはhttpsのURLに移動し、httpリクエストではリダイレクトが1回必要なので、IndexController.phpではリダイレクトを1回実行するだけです。


あなたの答えが質問をどのように解決するか説明できますか?
soundslikeodd

この説明を回答に追加してください。
サウンドライクオード2017


3

私はこの問題で非常に苦しんだので、この代替案を追加しています。私はいろいろな方法を試しましたが、何もうまくいきませんでした。それで、私はそれのための回避策を思いつきました。それは最善の解決策ではないかもしれませんが、うまくいきます-

参考までに、私はLaravel 5.6を使用しています

if (App::environment('production')) {
    URL::forceScheme('https');
}

本番<-.envファイルのAPP_ENV値で置き換える必要があります


2

Herokuでそれを行う方法は次のとおりです

ローカルではなく、dynoでSSLを強制するには、public /で.htaccessの最後に追加します。

# Force https on heroku...
# Important fact: X-forwarded-Proto will exist at your heroku dyno but wont locally.
# Hence we want: "if x-forwarded exists && if its not https, then rewrite it":
RewriteCond %{HTTP:X-Forwarded-Proto} .
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

これをローカルマシンでテストするには、次のようにします。

curl -H"X-Forwarded-Proto: http" http://your-local-sitename-here

これにより、ヘッダーがX転送され、herokuで使用されるフォームに設定されます。

つまり、heroku dynoがリクエストをどのように見るかをシミュレートします。

ローカルマシンでこの応答が得られます:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="https://tm3.localhost:8080/">here</a>.</p>
</body></html>

それはリダイレクトです。上記のように.htaccessを設定した場合、herokuはクライアントにそれを返します。しかし、X-forwardedが設定されていないため、ローカルマシンでは発生しません(何が発生しているかを確認するために、上のcurlで偽装しました)。


2

CloudFlareを使用している場合は、常にHTTPSを使用するページルールを作成できます。 SSL Cloudflareを強制する これにより、すべてのhttp://要求がhttps://にリダイレクトされます

それに加えて、次のようなものを\ app \ Providers \ AppServiceProvider.php boot()関数に追加する必要があります。

if (env('APP_ENV') === 'production' || env('APP_ENV') === 'dev') {
     \URL::forceScheme('https');
}

これにより、アプリ内のすべてのリンク/パスがhttp://ではなくhttps://を使用するようになります。


2

Laravel 5.7でテストされた、少し異なるアプローチ

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Str;

class ForceHttps
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {    
        if ( !$request->secure() && Str::startsWith(config('app.url'), 'https://') ) {
            return redirect()->secure($request->getRequestUri());
        }
        return $next($request);
    }
}

PS。@ matthias-lillのコメントに基づいてコードを更新しました。


1
Laravel 6でも動作します。
ルーベンス

1
env()関数の使用は、キャッシュされた構成ファイルでは機能しません。config('app.url')代わりにこれを指す必要があります。また、Laravelには非常に便利な文字列関数が付属していますStr::startsWith(config('app.url'), 'https://')
Matthias Lill

1

Laravel 5.6では、機能させるために状態を少し変更する必要がありました。

から:

if (!$request->secure() && env('APP_ENV') === 'prod') {
return redirect()->secure($request->getRequestUri());
}

に:

if (empty($_SERVER['HTTPS']) && env('APP_ENV') === 'prod') {
return redirect()->secure($request->getRequestUri());
}

1

これでうまくいきました。httpsに強制的にリダイレクトするカスタムphpコードを作成しました。header.phpにこのコードを含めるだけです

<?php
if (isset($_SERVER['HTTPS']) &&
    ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
    isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
    $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
  $protocol = 'https://';
}
else {
  $protocol = 'http://';
}
$notssl = 'http://';
if($protocol==$notssl){
    $url = "https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";?>
    <script> 
    window.location.href ='<?php echo $url?>';
    </script> 
 <?php } ?>

1

私はLaravel 5.6.28の次のミドルウェアで使用しています:

namespace App\Http\Middleware;

use App\Models\Unit;
use Closure;
use Illuminate\Http\Request;

class HttpsProtocol
{
    public function handle($request, Closure $next)
    {
        $request->setTrustedProxies([$request->getClientIp()], Request::HEADER_X_FORWARDED_ALL);

        if (!$request->secure() && env('APP_ENV') === 'prod') {
            return redirect()->secure($request->getRequestUri());
        }

        return $next($request);
    }
}

1

最も簡単な方法は、アプリケーションレベルです。ファイル内

app/Providers/AppServiceProvider.php

以下を追加します。

use Illuminate\Support\Facades\URL;

そしてboot()メソッドに以下を追加します:

$this->app['request']->server->set('HTTPS', true);
URL::forceScheme('https');

これにより、すべてのリクエストがアプリケーションレベルでhttpsにリダイレクトされます。

(注:これはlaravel 5.5 LTSでテストされています)


1

あなたは、に行くことができ、簡単なアプリ > - プロバイダ - > AppServiceProvider.phpは、

2行追加

Illuminate \ Support \ Facades \ URLを使用します。

URL :: forceScheme( 'https');

次のコードに示すように:

use Illuminate\Support\Facades\URL;

class AppServiceProvider extends ServiceProvider
{
   public function boot()
    {
        URL::forceScheme('https');

       // any other codes here, does not matter.
    }

0

Laravel 7.xでのこの作業は、3つの簡単なステップで実行できますミドルウェアを使用したし。

1)コマンドでミドルウェアを生成する php artisan make:middleware ForceSSL

ミドルウェア

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\App;

class ForceSSL
{
    public function handle($request, Closure $next)
    {
        if (!$request->secure() && App::environment() === 'production') {
            return redirect()->secure($request->getRequestUri());
        }

        return $next($request);
    }
}

2)ミドルウェアをrouteMiddlewareカーネルファイル内に登録する

カーネル

protected $routeMiddleware = [
    //...
    'ssl' => \App\Http\Middleware\ForceSSL::class,
];

3)ルートで使用する

ルート

Route::middleware('ssl')->group(function() {
    // All your routes here

});

ここにミドルウェアに関する完全なドキュメント

========================

.HTACCESSメソッド

.htaccessファイルを使用したい場合は、次のコードを使用できます。

<IfModule mod_rewrite.c>
    RewriteEngine On 
    RewriteCond %{SERVER_PORT} 80 
    RewriteRule ^(.*)$ https://yourdomain.com/$1 [R,L]
</IfModule>

よろしく!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.