Web

Laravel 5 — перенаправление на HTTPS

Работаю над своим первым проектом на Laravel 5 и не уверен, где и как разместить логику для принудительного HTTPS в моем приложении. Загвоздка в том, что на приложение указывает множество доменов, и только два из трех используют SSL (третий запасной домен). Поэтому я хотел бы сделать это в логике моего приложения, а не в .htaccess. В Laravel 4.2 я выполнил перенаправление с помощью этого кода, расположенного в filters.php:

App::before(function($request) {

    if( ! Request::secure()) {

        return Redirect::secure(Request::path());

    }

});

 Я думаю, что Middleware — это то место, где должно быть реализовано нечто подобное, но я не могу понять, как это сделать с его помощью.

Если вы используете Cloudflare, как я, это достигается путем добавления нового правила страницы в вашей панели управления.

 

Ответ 1

Вы можете заставить его работать с помощью класса Middleware. Позвольте мне дать вам идею:

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',

    // добавление пользовательского промежуточного ПО 

    'MyApp\Http\Middleware\HttpsProtocol'       

 

];

 В примере выше промежуточное ПО будет перенаправлять каждый запрос на https, если:

  1. Текущий запрос не имеет защищенного протокола (http).

  2. Если ваша среда является производственной. Поэтому просто настройте параметры в соответствии с вашими предпочтениями.

Cloudflare

Я использую этот код в производственной среде с WildCard SSL, и код работает правильно. Если я удалю && App::environment() === 'production' и протестирую его на localhost, перенаправление также работает. Таким образом, наличие или отсутствие установленного SSL не является проблемой. Похоже, что вам нужно очень внимательно следить за уровнем Cloudflare, чтобы получить перенаправление на протокол Https.

Также необходимо знать, что некоторые проблемы могут быть вызваны заголовками, которые передает Cloudflare. CloudFlare, вероятно, обращается к вашему серверу через HTTP и передает заголовок X-Forwarded-Proto, который заявляет, что он перенаправляет запрос HTTPS. Вам нужно добавить еще одну строку в Middleware:

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

чтобы доверять заголовкам, которые посылает CloudFlare. Это остановит цикл перенаправления.

Также нужно добавить класс middleware в веб-группу в файле kernel.php:

protected $middlewareGroups = [

    'web' => [

        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,

        \Illuminate\Session\Middleware\StartSession::class,

        \Illuminate\View\Middleware\ShareErrorsFromSession::class,

        // здесь

        \MyApp\Http\Middleware\HttpsProtocol::class

    ],

];

 Помните, что группа web применяется к каждому маршруту по умолчанию, поэтому вам не нужно явно задавать web ни в маршрутах, ни в контроллерах.

Для перенаправления запроса в зависимости от окружения вы можете использовать App::environment() === 'production'. Для предыдущей версии было env('APP_ENV') === 'production'.

Использование \URL::forceScheme('https'); фактически не перенаправляет. Он просто создает ссылки с https://, когда сайт отображается.

 

Ответ 2

Для laravel 5.4 используйте этот формат для получения перенаправления https вместо .htaccess:

namespace App\Providers;

use Illuminate\Support\Facades\URL;

use Illuminate\Support\ServiceProvider;

 

class AppServiceProvider extends ServiceProvider {

    public function boot() {

        URL::forceScheme('https');

    }

}

 

Ответ 3

Аналогично ответу manix, но в одном месте. Посредственное программное обеспечение для принудительного использования HTTPS:

namespace App\Http\Middleware;

use Closure;

use Illuminate\Http\Request;

 

class ForceHttps {

    /**

     * Обработка входящего запроса.

     *

     * @param \Illuminate\Http\Request $request

     * @param \Closure $next

     * @return mixed

     */

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

        if (!app()->environment('local')) {

            // для прокси-серверов

            Request::setTrustedProxies([$request->getClientIp()], 

                Request::HEADER_X_FORWARDED_ALL);

            if (!$request->isSecure()) {

                return redirect()->secure($request->getRequestUri());

            }

        }

        return $next($request);

    }

}

 

 Ответ 4

Как насчет того, чтобы просто использовать файл .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 изменит или удалит некоторые функции.

 

Ответ 5

Это касается Laravel 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,

];

 Далее я хочу защитить две основные группы login/signup и т. д., а все остальное за Auth middleware.

Route::group(array('middleware' => 'forceSSL'), function() {

/*авторизация пользователя*/

Route::get('login', 'AuthController@showLogin');

Route::post('login', 'AuthController@doLogin');

// Маршруты сброса пароля...

Route::get('password/reset/{token}', 'Auth\PasswordController@getReset');

Route::post('password/reset', 'Auth\PasswordController@postReset');

//другие маршруты, такие как регистрация и т.д.

});

Route::group(['middleware' => ['auth','forceSSL']], function() {

Route::get('dashboard', function(){

    return view('app.dashboard');

});

Route::get('logout', 'AuthController@doLogout');

//другие маршруты для вашего приложения

});

 Убедитесь, что ваши промежуточные модули правильно применены к вашим маршрутам из консоли.

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>

 При этом отображается полностью квалифицированный URL, например: https://yourhost/login и http://yourhost/aboutus.

Если бы вы не отображали полностью квалифицированный URL с http и использовали относительную ссылку url('/aboutus'), то https сохранился бы после посещения пользователем защищенного сайта.

 

Ответ 6

Немного другой подход, проверенный в Laravel 5.7:

<?php

namespace App\Http\Middleware;

use Closure;

use Illuminate\Support\Str;

 

class ForceHttps {

    /**

     * Обработка входящего запроса.

     *

     * @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);

    }

}

 

Схожие статьи

Web

Передача переменных JavaScript в PHP?

Web

Как выполнить загрузку файла с помощью сериализации jquery

Web

Преобразование изображения SVG в PNG с помощью PHP

Web

Применение выражения eval в php