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());
    }
});

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

Спасибо!

ОБНОВЛЕНИЕ

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

Author: NightMICU, 2015-02-09

16 answers

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

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. Итак, просто отрегулируйте настройки в соответствии с вашими предпочтениями.

Вспышка облака

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

Изменить 23/03/2015

Благодаря предложению @Adam Link: скорее всего, это вызвано заголовками эта вспышка облака проходит. CloudFlare, скорее всего, попадает на ваш сервер через HTTP и передает заголовок X-Forwarded-Proto, который объявляет, что он перенаправляет запрос HTTPS. Вам нужно добавить еще одну строку в ваше промежуточное программное обеспечение, в которой говорится...

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

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

Редактировать 27.09.2016 - 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 в маршрутах или контроллерах.

Редактировать 23.08.2018 - Laravel v5.7

  • Для перенаправления запроса в зависимости от среды вы можете использовать App::environment() === 'production'. Для предыдущей версии было env('APP_ENV') === 'production'.
  • Использование \URL::forceScheme('https'); на самом деле не перенаправляет. Он просто создает ссылки с https:// после того, как веб-сайт будет отображен.
 158
Author: manix, 2018-08-23 22:53:08

Другой вариант, который сработал для меня, в AppServiceProvider поместите этот код в метод загрузки:

\URL::forceScheme('https');

Функция, написанная до forceSchema('https'), была неправильной, ее forceScheme

 39
Author: Constantin Stan, 2017-11-02 12:02:49

В качестве альтернативы, если вы используете Apache, вы можете использовать файл .htaccess для принудительного использования ваших URL-адресов для использования префикса https. В Laravel 5.4 я добавил следующие строки в свой файл .htaccess, и это сработало для меня.

RewriteEngine On

RewriteCond %{HTTPS} !on
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
 12
Author: Assad Ullah Ch, 2017-04-26 12:07:08

Для 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');
    }
}
 10
Author: Arun Yokesh, 2017-04-28 09:50:51

Похоже на ответ маникса, но в одном месте. Промежуточное программное обеспечение для принудительного использования 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);
    }
}
 9
Author: Mladen Janjetovic, 2016-06-14 17:00:32

Это для 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,
];

Далее, я хотел бы защитить две основные группы входа/регистрации и т. Д. И все остальное за промежуточным программным обеспечением аутентификации.

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>

Что это делает, так это отображает полный URL-адрес, такой как https://yourhost/login и http://yourhost/aboutus

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

Надеюсь, это поможет!

 4
Author: na-98, 2016-08-27 14:45:55

В 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 каждый редирект будет переходить на url https, и для http-запроса нам нужно один раз перенаправить , поэтому в IndexController.php Просто нам нужно сделать один раз перенаправление

 3
Author: Artur Qaramyan, 2017-02-05 19:22:41

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

 3
Author: Maulik Gangani, 2017-06-09 01:32:04

Приведенные выше ответы не сработали для меня, но, похоже, Дениз Туран переписал .htaccess таким образом, чтобы он работал с балансировщиком нагрузки Heroku здесь: https://www.jcore.com/2017/01/29/force-https-on-heroku-using-htaccess/

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
 2
Author: Phil, 2017-12-13 14:50:28

Вот как это сделать на Heroku

Чтобы принудительно использовать SSL на вашем компьютере, но не локально, добавьте в конец вашего.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.

Т.е. он имитирует, как дино героку увидит запрос.

Вы получите этот ответ на своем локальном компьютере:

<!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, как указано выше. Но это не происходит на вашем локальном компьютере, потому что X-перенаправление не будет установлено (мы подделали его с помощью curl выше, чтобы посмотреть, что происходит).

 1
Author: mwal, 2018-02-20 17:32:02

Для 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
Author: Priyank, 2018-04-29 11:08:58

Вы можете использовать RewriteRule для принудительного использования ssl в.htaccess в той же папке, что и ваш index.php
Пожалуйста, добавьте как прикрепленное изображение, добавьте его перед тем, как все остальные правила setting ssl .htaccess

 1
Author: Quy Le, 2018-06-01 04:47:30

Это сработало для меня. Я сделал пользовательский php-код, чтобы принудительно перенаправить его на https. Просто включите этот код в 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
Author: Geeky Ashim, 2018-07-03 19:04:32

Если вы используете CloudFlare, вы можете просто создать правило страницы, чтобы всегда использовать HTTPS: Force SSL Cloudflare Это перенаправит каждый http://запрос на https://

В дополнение к этому вам также придется добавить что-то подобное в свой \app\Providers\AppServiceProvider.php функция загрузки():

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

Это гарантирует, что каждая ссылка/путь в вашем приложении использует https:// вместо http://.

 1
Author: butaminas, 2018-07-05 21:24:04

Я использую в 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
Author: fomvasss, 2018-07-30 15:35:39

Я добавляю эту альтернативу, так как я много страдал из-за этой проблемы. Я пробовал все разные способы, но ничего не получалось. Итак, я придумал обходной путь для этого. Возможно, это не лучшее решение, но оно действительно работает -

К вашему сведению, я использую Laravel 5.6

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

Производство

 0
Author: thebrownkid, 2018-07-21 11:10:35