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, если:
- текущий запрос поставляется без безопасного протокола (http)
- если ваша среда равна
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());
}
это сработало для меня. Я сделал пользовательский 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: Это будет перенаправлять каждого 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