Laravel5-重定向到 HTTPS

工作在我的第一个 Laravel5项目,不确定在哪里或如何放置逻辑强制 HTTPS 在我的应用程序。这里的关键是有许多域指向应用程序,三分之二的域使用 SSL (第三个域是后备域,说来话长)。所以我想用我的应用程序的逻辑来处理这个问题。Htaccess.

在 Laravel 4.2中,我用 filters.php中的代码完成了重定向:

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

我认为中间件是应该实现这样的东西,但我不能完全弄清楚使用它。

谢谢!

更新

如果您像我一样使用 Cloudflare,那么可以通过在控制面板中添加一个新的 Page Rule 来实现。

262512 次浏览

你可以使用一个中间件类。让我给你一个想法。

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,那么,根据你的喜好调整设置。

云烟

我在带有 WildCard SSL 的生产环境中使用这段代码,并且这段代码可以正常工作。如果我删除 && App::environment() === 'production'并在 localhost 中测试它,重定向也可以工作。因此,是否安装了 SSL 并不是问题所在。看起来您需要非常关注您的 Cloudflare 层,以便将其重定向到 Https 协议。

编辑23/03/2015

感谢 @Adam Link的建议: 它很可能是由 Cloudflare 传递的头引起的。CloudFlare 可能通过 HTTP 访问您的服务器,并传递一个 X-Forward-Proto 头,该头声明它正在转发一个 HTTPS 请求。您需要在中间件中添加另一行说..。

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

信任 CloudFlare 正在发送的报头,这将停止重定向循环

编辑27/09/2016-Laravel v5.3

只需要将中间件类添加到 kernel.php fileweb组中:

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://一旦网站呈现链接。

类似于 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()],
Request::HEADER_X_FORWARDED_ALL);


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>

非安全链接可以呈现为

<a href="\{\{url('/aboutus',[],false)}}">About US</a></li>
<a href="\{\{url('/promotion',[],false)}}">Get the deal now!</a></li>

这样做的目的是呈现一个完全限定的 URL,比如 https://yourhost/loginhttp://yourhost/aboutus

如果你没有呈现完全限定的网址与 http 和使用一个相对链接的网址(’/about us’) ,那么 https 将持续后,用户访问一个安全的网站。

希望这个能帮上忙!

在 AppServiceProvider 中,另一个适合我的选项是将这段代码放在 boot 方法中:

\URL::forceScheme('https');

写在 forcSchema (‘ https’)之前的函数是错误的,它的 forcScheme

在 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::forceScheme('https');

}

在 AppServiceProvider.php 中,每个重定向都会转到 URL https,对于 HTTP 请求,我们需要重定向一次,所以在 IndexController.php 中,我们只需要重定向一次。

您特别不需要执行 IndexController.php 中提到的工作,它是重定向上的一个额外控件。

使用 . 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 改变或删除一些功能。

或者,如果您正在使用 Apache,那么您可以使用 .htaccess文件来强制您的 URL 使用 https前缀。在 Laravel 5.4上,我在 .htaccess文件中添加了以下代码行,它对我很有用。

RewriteEngine On


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

对于 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');
}
}

上面的答案对我不起作用,但是看起来 Deniz Turan 重写了。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,但不是在本地,请在 public/中添加到. 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。

也就是说,它模拟了 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>

这是重定向。这就是 heroku 将返回给客户端的内容,如果您设置。Htaccess 如上。但是它不会发生在您的本地机器上,因为 X- 转发不会被设置(我们在上面使用 curl 来伪造它,以查看发生了什么)。

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

您可以使用 RewriteRule 强制. htaccess 中的 ssl 与 index.php 位于同一个文件夹
请添加为图片附加,添加前所有规则其他人 setting ssl .htaccess

这招对我管用。 我做了一个自定义的 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 } ?>

如果您正在使用 CloudFlare,您可以创建一个 Page Rule 来始终使用 HTTPS: Force SSL Cloudflare 这将把每个 http://请求重定向到 https://

除此之外,您还需要向应用程序 Provider AppServiceProvider.php boot ()函数添加类似的内容:

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

这将确保应用程序中的每个链接/路径都使用 https://而不是 http://。

我加入这个备选方案是因为我在这个问题上遭受了很多。我试了各种方法,都没用。所以我想到了一个解决办法。这可能不是最好的解决方案,但它的工作-

仅供参考,我用的是 Laravel 5.6

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

Production <-应该用. env 文件中的 APP _ ENV 值替换

我正在使用 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);
}
}

最简单的方法是在应用程序级别

app/Providers/AppServiceProvider.php

加入以下内容:

use Illuminate\Support\Facades\URL;

在 boot ()方法中添加以下内容:

$this->app['request']->server->set('HTTPS', true);
URL::forceScheme('https');

这应该在应用程序级别将所有请求重定向到 https。

(注意: 这已经用幼虫5.5 LTS 测试过了)

一个不同的方法,在 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 的注释更新代码。

我在 3个简单的步骤Laravel7.x中使用一个中间件:

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中间件

内核

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>

问候!

你可以简单地转到 应用程序-> 供应商-> AppServiceProvider.php

加两行

使用照明支持立面网址;

网址: : forcScheme (‘ https’) ;

如下列守则所示:

use Illuminate\Support\Facades\URL;


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


// any other codes here, does not matter.
}

在 Laravel 5.1中,我使用了: 文件: app Provider AppServiceProvider.php

public function boot()
{
if ($this->isSecure()) {
\URL::forceSchema('https');
}
}


public function isSecure()
{
$isSecure = false;
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
$isSecure = true;
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
$isSecure = true;
}


return $isSecure;
}

注意: 使用 forceSchema,而不是 forceScheme

使用 Laravel 重定向到 HTTPS 的最简单方法是使用. htaccess

所以你要做的就是将下面的代码行添加到。你可以访问 htaccess 文件了。

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

请确保在. htaccess 文件中的现有 (*default)代码之前添加它,否则 HTTPS 将无法工作。 这是因为现有的(默认)代码已经处理了一个重定向,该重定向将所有流量重定向到主页,然后路由根据您的 URL 接管主页

因此,把代码放在第一位意味着. htaccess 将在路由接管之前首先将所有流量重定向到 https

我发现这对我很有用。首先把这段代码拷贝到 .htaccess文件中。

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>