Laravel 5 - переадресація на HTTPS


127

Працюю над моїм першим проектом Laravel 5 і не знаю, де або як розмістити логіку, щоб змусити HTTPS в моєму додатку. Тут є дуже багато доменів, що вказують на додаток, і лише два з трьох використовують SSL (третій - резервний домен, довга історія). Тому я хотів би вирішити це в логіці свого додатка, а не .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']
Визначивши

Скільки часу
знадобилося набуття

О, мені довелося ввімкнути проксі в налаштуваннях DNS ха-ха!
CodeGuru

Відповіді:


253

Ви можете змусити його працювати з класом 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',

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

];

На прикладі вище, проміжне програмне забезпечення буде перенаправляти кожен запит на https, якщо:

  1. Поточний запит постачається без захищеного протоколу (http)
  2. Якщо ваше оточення дорівнює production. Отже, просто відрегулюйте налаштування відповідно до своїх уподобань.

Cloudflare

Я використовую цей код у виробничому середовищі з SSL WildCard, і код працює правильно. Якщо я видаляю && App::environment() === 'production'і тестую його у localhost, перенаправлення також працює. Отже, наявність або не встановлений SSL не є проблемою. Схоже, вам потрібно дуже уважно стежити за своїм шаром Cloudflare, щоб перенаправитись на протокол Https.

Редагувати 23.03.2015

Завдяки @Adam Linkпропозиції: хедери, ймовірно, спричинені проходженням Cloudflare. 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://як тільки веб-сайт надається.

5
Це, здається, дає мені цикл переадресації ... схоже, це має працювати, хоча. Я не знаю, чи має це значення, але ми використовуємо SSL Cloudflare. Але я не думаю, що це змінило б просте перенаправлення.
NightMICU

3
@NightMICU Я не впевнений, чи ви вирішили проблему з переадресацією, але це, ймовірно, викликане заголовками, що Cloudflare проходить. CloudFlare, ймовірно, потрапляє на ваш сервер через HTTP і передає заголовок X-Forwarded-Proto, який заявляє, що він пересилає HTTPS-запит. Вам потрібно додати ще один рядок у своє програмне забезпечення Middleware, яке говорить про те, $request->setTrustedProxies( [ $request->getClientIp() ] );щоб довіряти заголовкам, які CloudFlare надсилає. Це зупинить цикл переадресації.
Адам Посилання

2
@manix Awesome Щойно пройшов цей випуск HTTPS в ці вихідні разом з моїм власним проектом - ця дрібничка буде вас засмучувати годинами!
Адам Посилання

8
Відмінна відповідь! Лише одна деталь: краще використовувати переспрямування 301, щоб вказати Google, що це постійний рух. Як:return redirect()->secure($request->getRequestUri(), 301);
Адріарока

4
для тих, хто під балансуванням навантаження або проксі може змінити, щоб захистити (), $request->server('HTTP_X_FORWARDED_PROTO') != 'https'це працює для мене
Широ

63

Інший варіант, який працював для мене, в AppServiceProvider помістіть цей код у методі завантаження:

\URL::forceScheme('https');

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


16
Гей, щойно це знайшли через гуглінг навколо - зауважте, що в 5.4 це\URL::forceScheme('https');
дев

5
У цьому ж файлі ви також можете зробитиif($this->app->environment() === 'production'){ $this->app['request']->server->set('HTTPS', true); }
Рорі

2
мав на увазі\URL::forceScheme('https')
Ернест Окот

17
Я майже впевнений, що це стосується лише побудови посилань. Це не змусить користувача скористатися https, воно буде обслуговувати лише посилання, попередньо встановлені https: //
Weston Watson

так, це сталося @WestonWatson будь ласка, поділіться рішенням, якщо його знайдуть
Харат

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 для всіх.
Младен Яньєтович

@MladenJanjetovic ви можете використовувати RewriteCond %{HTTP_HOST} !=localhostна Dev, щоб обійти це.
Dan

3
@Dan - Так, але вам все одно доведеться встановити його для місцевого етапу (і це складніше, якщо розробники використовують різні URL-адреси в локальній розробці, тобто .dev, .local, субдомени, ... і т.д.). Я вважаю за краще мати таку логіку в додатку.
Младен Яньєтович

16

для 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');
    }
}

15
Просто для уточнення: 1) ці зміни слід зробити в додатку / Провайдерах / AppServiceProvider.php; 2) це лише для встановлення посилань, створених у додатку, для використання SSL, це не змушує вас використовувати SSL
Phoenix

Привіт, Маршрут не генерується цим методом, якщо я натискаю кнопку, яка пересилає мене до наступного маршруту, не дає мені помилки 404
Saket Sinha

Це не перенаправлення https. Але це дозволяє обслуговувати сайт https: //. Якщо змінити його на http: //, він також буде служити.
франк

12

Схожа на відповідь Манікса, але в одному місці. Посереднє програмне забезпечення для застосування 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,
];

Далі, я хотів би забезпечити дві основні групи для входу / реєстрації тощо та все інше, що стоїть за програмним забезпеченням 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>

Для цього потрібно отримати повністю кваліфіковану URL-адресу, наприклад https: // yourhost / login та http: // yourhost / aboutus

Якщо ви не надавали повністю кваліфіковану 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 дає мені помилку: Занадто багато переадресацій. Схоже, це робить цикл
Phoenix

Привіт, я оновив відповідь. Переконайтеся, що ви помістили цей .htaccess у кореневий каталог проекту та вкажіть ваш сервер (apache config) на проект root.
Maulik Gangani

1
@MladenJanjetovic ви можете мати різні файли htaccess для цих середовищ
Бургі

1
@MladenJanjetovic наявність цього в додатку безумовно має свої переваги, але з точки зору ефективності та швидкості я б сказав, що це вигідніше мати конфігурацію сервера, щоб вам не довелося завантажувати Laravel просто для переадресації. Конфігурації для оточуючого середовища в єдиному варіанті .htaccess можна досягти, скориставшись умовою переписання для перевірки домену, на кшталтRewriteCond %{HTTP_HOST} productiondomain\.com$ [NC]
Chris

1
Я теж вважаю за краще розміщувати це у .htaccess у кореневому каталозі, і, як сказав Crhis, тут можна виконати налаштування, що стосуються середовища, хоч і трохи менш елегантно, ніж у рішеннях Младена.
Іван

6

Ви можете використовувати RewriteRule, щоб змусити ssl у .htaccess одній папці з вашим index.php.
Будь ласка, додайте як додавання до зображення, додайте її до того, як усі правила інших встановлення ssl .htaccess


3

в IndexController.php put

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 Просто нам потрібно зробити один раз переадресацію


Чи можете ви пояснити, як ваша відповідь вирішує питання?
soundlikeodd

Будь ласка, додайте це пояснення до своєї відповіді.
soundlikeodd

3

Наведені вище відповіді не працювали для мене, але, здається, Деніз Туран переписав .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]

3

Я додаю цю альтернативу, оскільки я сильно пережив це питання. Я пробував всі різні способи, і нічого не вийшло. Отже, я придумав це рішення. Це може бути не найкращим рішенням, але воно працює -

FYI, я використовую Laravel 5.6

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

production <- Його слід замінити значенням APP_ENV у файлі .env


2

Ось як це зробити на 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 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 не буде встановлена ​​(ми підробили це за допомогою згортання, щоб побачити, що відбувається)


2

Якщо ви використовуєте CloudFlare, ви можете просто створити правило сторінки, щоб завжди використовувати HTTPS: Примусовий SSL Cloudflare Це переспрямує кожен http: // запит на https: //

На додаток до цього, вам також доведеться додати щось подібне до функції \ app \ Providers \ AppServiceProvider.php boot ():

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

Це забезпечить, щоб кожне посилання / шлях у вашій програмі використовували https: // замість http: //.


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://').
Маттіас Лілл

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

Це вийшло для мене. Я зробив спеціальний 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

Я використовую 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

додайте два рядки

використовувати освітлювальну \ підтримку \ фасади \ 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файлі Kernel

Ядро

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>

З повагою!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.