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

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

в Laravel 4.2 я выполнил перенаправление с помощью этого кода, расположенного в filters.php:

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

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

спасибо!

обновление

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

16 ответов


вы можете заставить его работать с классом 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); 
    }
}

затем примените это промежуточное ПО к каждому запросу, добавляя установку правила в , например:

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. Так, как раз отрегулируйте установки согласно ваше пожелание.

Cloudflare

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

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

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

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

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

Edit 27/09/2016-Laravel v5.3

просто нужно добавить класс middleware в 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 явно в маршрутах и контроллерах.

Edit 23/08/2018-Laravel v5.7

  • для перенаправления запроса в зависимости от окружающей среды вы можете использовать App::environment() === 'production'. Для предыдущей версии был env('APP_ENV') === 'production'.
  • используя \URL::forceScheme('https'); фактически не перенаправляет. Он просто строит связи с https:// после отображения веб-сайта.

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

\URL::forceScheme('https');

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


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

RewriteEngine On

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

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

namespace App\Providers;

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

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

похоже на ответ manix, но в одном месте. Промежуточное ПО для принудительного 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);
    }
}

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

далее, я хотел бы защитить две основные группы входа / регистрации и т. д. И все остальное за 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>

Non безопасные соединения можно представить как

<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 будет сохраняться после посещения пользователем безопасного сайта.

надеюсь, что это помогает!


в IndexController.php put

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

        return redirect('/');
    }

    return view('index');
}

в AppServiceProvider.php put

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

}

В AppServiceProvider.php каждый редирект будет идти на url https и для http-запроса нам нужно один раз перенаправить так в IndexController.php просто нужно сделать один раз redirect


Как насчет просто с помощью .реврайт файл для достижения перенаправления 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/ [L]
</IfModule>

Я использую это для laravel 5.4 (последняя версия на момент написания этого ответа), но он должен продолжать работать для версий функций, даже если laravel изменяет или удаляет некоторые функции.


ответы выше не сработали для меня ,но похоже, что Дениз Туран переписал.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]

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

чтобы принудительно SSL на вашем dynos, но не локально, добавьте в конец вашего .htaccess in public/:

# 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-forwarded в форму, которую он примет на 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>

это перенаправление. Это то, что heroku собирается вернуть клиенту, если вы установите .htaccess, как указано выше. Но это не происходит на вашем локальном компьютере, потому что X-forwarded не будет установлен (мы подделали его с завитком выше, чтобы увидеть, что происходит).


для Laravel 5.6 мне пришлось немного изменить состояние, чтобы заставить его работать.

from:

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

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


это сработало для меня. Я сделал пользовательский php-код, чтобы перенаправить его на https. Просто включите этот код в заголовок.в 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 } ?>

Если вы используете 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://.


Я использую в 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);
    }
}

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

FYI, я использую Laravel 5.6

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

production