Laravel 5 - 重定向到HTTPS

时间:2015-02-09 04:14:43

标签: php laravel laravel-routing laravel-5

处理我的第一个Laravel 5项目,并且不确定在我的应用上强制使用HTTPS的逻辑位置或方式。这里的关键是有许多域指向应用程序,只有三分之二使用SSL(第三个是后备域,长篇故事)。所以我想在我的应用程序的逻辑中处理这个问题,而不是.htaccess。

在Laravel 4.2中,我使用此代码完成了重定向,位于filters.php

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

我认为中间件应该在这样的地方实现,但我无法用它来解决这个问题。

谢谢!

更新

如果您像我一样使用Cloudflare,可以通过在控制面板中添加新的页面规则来实现。

23 个答案:

答案 0 :(得分:202)

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

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。因此,只需根据您的喜好调整设置即可。
  3. 的CloudFlare

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

    编辑23/03/2015

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

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

    ...信任CloudFlare正在发送的标头。这将停止重定向循环

    编辑2016年9月27日 - 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://建立链接。

答案 1 :(得分:49)

另一个适用于我的选项,在AppServiceProvider中将此代码放在引导方法中:

\URL::forceScheme('https');

在forceScheme(' https')之前编写的函数错误,其forceScheme

答案 2 :(得分:23)

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

RewriteEngine On

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

答案 3 :(得分:13)

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

答案 4 :(得分:10)

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

答案 5 :(得分:6)

这适用于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>

这样做会呈现一个完全限定的网址,例如https://yourhost/loginhttp://yourhost/aboutus

如果您没有使用http呈现完全限定的网址并使用相对链接网址('/ aboutus'),则在用户访问安全网站后,https会一直存在。

希望这有帮助!

答案 6 :(得分:5)

您可以使用RewriteRule强制ssl在.htaccess与index.php相同的文件夹中
请添加为图片附加,在所有规则之前添加 setting ssl .htaccess

答案 7 :(得分:5)

使用 .htaccess 文件实现https重定向怎么样?这应该放在项目根目录中(不在公用文件夹中)。您的服务器需要配置为指向项目根目录。

\root
\root\index.php
\root\load.php

我将此用于laravel 5.4(编写此答案时的最新版本),但即使laravel更改或删除某些功能,它仍应继续用于功能版本。

答案 8 :(得分:3)

上面的答案对我不起作用,但似乎Deniz Turan以与Heroku的负载均衡器一起使用的方式重写.htaccess: 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]

答案 9 :(得分:3)

在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中我们需要做一次重定向

答案 10 :(得分:1)

以下是如何在Heroku上执行此操作

要在您的dynos上强制使用SSL而不是在本地强制使用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-forward设置为将在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>

这是重定向。如果您将.htaccess设置为如上所述,那就是heroku将返回给客户端的内容。但它不会发生在您的本地计算机上,因为X-forwarded将不会被设置(我们用上面的卷曲伪造它以查看发生了什么)。

答案 11 :(得分: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());
}

答案 12 :(得分: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 } ?>

答案 13 :(得分:1)

如果您正在使用CloudFlare,则可以创建一个页面规则以始终使用HTTPS: Force SSL Cloudflare 这会将每个http://请求重定向到https://

除此之外,您还必须在\ app \ Providers \ AppServiceProvider.php boot()函数中添加以下内容:

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

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

答案 14 :(得分:1)

我正在添加此替代方法,因为我在这个问题上受了很多苦。我尝试了所有不同的方式,但没有任何效果。因此,我想出了一种解决方法。它可能不是最好的解决方案,但确实有效-

  

仅供参考,我使用的是Laravel 5.6

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

生产<-应该用.env文件中的APP_ENV值替换

答案 15 :(得分: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);
    }
}

答案 16 :(得分:1)

稍有不同的方法,已在Laravel 5.7中进行了测试

<?php

namespace App\Http\Middleware;

use Closure;

class ForceHttps
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $app_url = env('APP_URL');

        if ( !$request->secure() && substr($app_url, 0, 8) === 'https://' ) {
            return redirect()->secure($request->getRequestUri());
        }
        return $next($request);
    }
}

答案 17 :(得分:1)

您可以简单地转到 app -> 提供商-> AppServiceProvider.php

添加两行

使用Illuminate \ Support \ Facades \ 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.
    }

答案 18 :(得分:1)

在Laravel 5.1中,我使用了: 文件:app \ Providers \ 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

答案 19 :(得分:0)

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

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进行了测试)

答案 20 :(得分:0)

使用中间件通过 3个简单步骤 Laravel 7.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

});

此处是有关middlewares的完整文档

======================

.HTACCESS方法

如果您更喜欢使用.htaccess文件,则可以使用以下代码:

<IfModule mod_rewrite.c>
    RewriteEngine On 
    RewriteCond %{SERVER_PORT} 80 
    RewriteRule ^(.*)$ https://yourdomain.com/$1 [R,L]
</IfModule>

致谢!

答案 21 :(得分:0)

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

所以你所要做的就是将以下几行添加到你的 .htaccess 文件中,你就可以开始了。

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

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

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

答案 22 :(得分:0)

我发现这对我有用。首先将此代码复制到 .htaccess 文件中。

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