【问题标题】:Laravel Redirect All Requests To HTTPSLaravel 将所有请求重定向到 HTTPS
【发布时间】:2013-11-26 21:08:47
【问题描述】:

我们的整个网站将通过 https 提供服务。我在每条路线中都有“https”。但是,如果他们通过 http 尝试重定向,我该如何将他们重定向到 https?

Route::group(array('https'), function()
{
     // all of our routes
}

【问题讨论】:

  • 正如许多人所说,这可以(而且 IMO 应该)由 Web 服务器(NGINX、Apache 等)完成。

标签: laravel-4


【解决方案1】:

使用 App::before

您也许可以利用app/filters.php 文件中的App::before() 块。

更改块以包含一个简单的检查以查看当前请求是否安全,如果不安全,则将其重定向。

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

使用过滤器

另一种选择可能是像这样创建一个过滤器。人们通常也将其存储在app/filters.php

Route::filter('force.ssl', function()
{
    if( ! Request::secure())
    {
        return Redirect::secure(Request::path());
    }

});

然后,您可以对任何路由、路由组或控制器强制执行该新过滤器。

个别路线

Route::get('something', ['before' => 'force.ssl'], function()
{
    return "This will be forced SSL";
});

路由组

Route::group(['before' => 'force.ssl'], function()
{
    // Routes here.
});

控制器

您需要在控制器的 __construct() 方法中执行此操作。

public function __construct()
{
    $this->beforeFilter('force.ssl');
}

【讨论】:

  • 这正是我想要的!我知道有一种方法可以在 Laravel 过滤器中干净地做到这一点。干杯
  • 使用 Request::path(),而不是 Request::getRequestUri()
  • 我一直在使用这个方法,但是今天我跑了apt-get upgrade之后它突然停止工作了。现在我收到一个路由错误:“在第 1528 行对 vendor/laravel/framework/src/Illuminate/Routing/Router.php 中的非对象调用成员函数 getAction()”。如果我注释掉重定向,它工作正常。
  • 这不应该在 Laravel 中完成,而应该在 .htaccess 中处理。运行 Laravel 不需要额外的开销来执行此操作。
  • 对于 Laravel 5 及更高版本,请查看此解决方案 stackoverflow.com/a/28403907/1340784
【解决方案2】:

另一个答案可能是让您的网络服务器处理这个问题。如果您使用的是 Apache,您可以使用 RedirectSSL 功能来确保所有请求都转到您网站的 HTTPS 版本,如果没有重定向它们。这将在 Laravel 收到请求之前发生。

Apache RedirectSSL

如果您使用 NGINX,则可以通过两个服务器块来完成此操作。一个用于端口 80 上的普通 HTTPS,另一个用于端口 443 上的 HTTPS。然后将普通服务器块配置为始终重定向到 ssl 版本。

server {
    listen 80;
    server_name mydomain.com;
    rewrite ^ https://$server_name$request_uri? permanent;
}

server {
    listen 443;
    server_name mydomain.com;
    ssl on;
    # other server config stuff here.
}

我个人会选择这个选项,因为 PHP 本身不需要处理任何东西。在网络服务器级别处理这样的支票通常更便宜。

【讨论】:

  • 澄清一下,我认为这个答案是首选的做事方式,而不是公认的答案。
  • 是的,在应用程序中这样做更耗时,因为(这样做)框架已经为每个http请求初始化,但在服务器conf中没有。我会使用 nginx 作为代理和 X_FORWARDED_PROTO 标头
  • 我的理念:信任 Web 服务器重定向,但在应用程序中验证。这样,您就可以两全其美。当 Web 服务器为您执行此操作时,应用程序的性能不会受到影响。当网络服务器没有(例如,配置错误)时,应用程序充当安全网,性能损失非常值得权衡。
【解决方案3】:

对于使用 Laravel 4/5 和 Elastic Beanstalk 的用户,使用这些方法很难强制使用 HTTPS,因为 isSecure() 将返回 false。此外,使用.htaccess 重定向将导致 Chrome 出现重定向循环并延迟 Firefox 中的页面加载时间。

此设置适用于

  • Laravel 5 并且可能适用于 Laravel 3 / 4
  • 应用程序加载到运行 EC2 服务器实例的 Elastic Beanstalk 上
  • 用于 DNS 解析的 Route 53
  • Cloudfront 用于所有资产的全球 CDN 并强制执行 HTTPS
  • 我在 Windows 机器上运行 aws。 Linux 可能略有不同?

经过我自己几个小时的尝试,我设法使用以下步骤将所有 HTTP 请求转发到 HTTPS:

  1. 获取 SSL 证书。指南和提供者众多,可通过 Google 搜索找到。

  2. 使用aws 控制台命令将证书上传到 AWS。命令结构为:

    aws iam upload-server-certificate --server-certificate-name CERTIFICATE_NAME --certificate-body "file://PATH_TO_CERTIFICATE.crt" --private-key "file://YOUR_PRIVATE_KEY.pem" --certificate-chain "file://YOUR_CERTIFICATE_CHAIN.ca-bundle" --path /cloudfront/
    
  3. 创建一个 Elastic Beanstalk 应用程序。继续完成设置过程。设置应用程序后,转到配置 -> 网络层 -> 负载平衡并点击齿轮图标 .

  4. 选择安全侦听器端口作为443。选择 Protocol 作为 HTTPS。从步骤 2 中为 SSL 证书 ID 选择 CERTIFICATE_NAME。保存配置。

  5. 转到您的控制台。点击 EC2 实例。点击负载平衡器。单击负载均衡器。单击 Instances 并向下滚动以查看分配给该负载均衡器的 EC2 实例。如果 EC2 实例与您的应用程序 URL 具有相同的名称(或类似名称),请记下负载均衡器的 DNS 名称。格式应为awseb-e-...

  6. 返回您的控制台。单击 CloudFront。点击创建分发。选择一个Web分发版。

  7. 设置分发。将您的 Origin Domain Name 设置为您在 步骤 5 中找到的负载平衡器 DNS 名称。将查看器协议政策设置为将 HTTP 重定向到 HTTPS。将 Forward Query Strings 设置为 Yes。将备用域名 (CNAME) 设置为您要用于您的应用程序的 URL。将 SSL 证书 设置为您在步骤 2 中上传的CERTIFICATE_NAME。创建您的发行版。

  8. 在 CloudFront 中单击您的分配名称。点击Origins,选择您的来源,然后点击Edit。确保您的 Origin Protocol PolicyMatch Viewer。回去。点击Behaviors,选择您的来源,然后点击Edit。将 Forward Headers 更改为 Whitelist 并添加 Host。保存。

  9. 转到您的控制台。点击53 号公路。点击托管区域。点击创建托管区域。设置您的域名。设置完成后,单击创建记录集。输入您的 A 记录。选择别名作为。您的别名目标是您的 CloudFront 分配。保存记录。

  10. 为您的域设置名称服务器以指向 Route 53 名称服务器。等待一切传播,这可能需要几个小时。转到您的网址。您将被自动重定向到 HTTPS。

  11. “但是等等,我的链接没有转到 HTTPS!?”您需要处理 CloudFront 将传递的 X-Forwarded-Proto 标头。对于 Laravel 4,follow this guide。对于 Laravel 5,运行这个:

    php artisan make:middleware EB_SSL_Trust
    

然后将其添加到EB_SSL_Trust 文件中:

    public function handle($request, Closure $next)
    {
        $request->setTrustedProxies( [ $request->getClientIp() ] );
        return $next($request);
    }

并将其添加到您的 App\Http\Kernel.php 文件中:

    protected $middleware = [
        ...
        'App\Http\Middleware\EB_SSL_Trust',
        ...
    ];

注意:您的所有资产,例如 CSS、JS 或图像,都需要通过 HTTPS 发送。如果您使用 Laravel 创建这些链接,请使用 secure_asset() 在您的视图中创建 HTTPS URL。

【讨论】:

    【解决方案4】:

    过滤器的使用已在 Laravel 5.1.* 中被弃用。对于中间件来说,这是一项完美的工作。

    创建一个中间件并在句柄部分放置

    public function handle($request, Closure $next)
    {
        if(! $request->secure()) {
            return redirect()->secure($request->path());
        }
        return $next($request);
    }
    

    然后只需在您的 Kernel.php 中注册您的中间件并将其与您的路由或控制器一起使用。

    【讨论】:

      【解决方案5】:

      在 laravel 4.2.X 中使用 .htaccess Apache

      原始文件

      <IfModule mod_rewrite.c>
          <IfModule mod_negotiation.c>
              Options -MultiViews
          </IfModule>
      
          RewriteEngine On
      
          # Redirect Trailing Slashes...
          RewriteRule ^(.*)/$ /$1 [L,R=301]
      
          # Handle Front Controller...
          RewriteCond %{REQUEST_FILENAME} !-d
          RewriteCond %{REQUEST_FILENAME} !-f
          RewriteRule ^ index.php [L]
      </IfModule>
      

      编辑文件/public/.htaccess

       <IfModule mod_rewrite.c>
          <IfModule mod_negotiation.c>
              Options -MultiViews
          </IfModule>
      
          RewriteEngine On
      
          # Redirect Trailing Slashes...
          RewriteCond %{HTTPS} off 
          RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] 
      
      
          # Handle Front Controller...
          RewriteCond %{REQUEST_FILENAME} !-d
          RewriteCond %{REQUEST_FILENAME} !-f
          RewriteRule ^ index.php [L]
      </IfModule>
      

      【讨论】:

      • 但这不会删除尾部斜杠。也许这条规则更合适:RewriteRule ^(.*[^/]|)/*$ https://%{HTTP_HOST}/$1 [L,R=301]。当它不安全时(带有或不带有斜杠),它会正确重定向。还需要维护原始重定向,以便在协议正确但存在尾部斜杠时进行匹配。
      • 删除# Redirect Trailing Slashes... RewriteRule ^(.*)/$ /$1 [L,R=301]
      【解决方案6】:

      结合以前的答案并更新 Laravel 4.2:

      Route::filter('secure', function () {
          if (! Request::secure()) {
              return Redirect::secure(
                  Request::path(),
                  in_array(Request::getMethod(), ['POST', 'PUT', 'DELETE']) ? 307 : 302
              );
          }
      });
      Route::when('*', 'secure');
      

      【讨论】:

      • 仅供参考,Route::filter 代码位于 filters.php 中,Route::when 代码位于 routes.php 中。我只是想保护我网站的一部分,所以我添加了Route::when('admin/*', 'secure');
      【解决方案7】:

      如果你想重定向到同一个 URL 但使用 https,你应该使用 Request::getRequestUri() 而不是 Request::path()

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

      【讨论】:

        【解决方案8】:

        这在 Apache 2.4 中对我有用

        我更改了 Laravel 根文件夹中的 .htaccess

        <IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^(.*)$ public/$1 [L] </IfModule>

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

        【讨论】:

          【解决方案9】:

          如果您遇到问题,由于某种原因 Request::secure() 返回 false,即使 url 是 https,也可能是因为 $_SERVER['HTTPS'] 值不存在。

          这是一种解决方法:

          App::before(function ($request){
              // Force https
              if(!Request::secure() && array_get($_SERVER, 'SERVER_PORT') != 443){
                  return Redirect::secure(Request::path());
              }
          });
          

          【讨论】:

            【解决方案10】:

            我在执行 POST 请求时遇到了强制使用 ssl 的问题。它总是会重定向到 GET。这是因为 Redirect::secure() 默认使用 302 重定向。

            要确保正确重定向您的 POST 请求,请使用类似

            的内容
            return Redirect::secure("your/path/here", 307)
            

            这将确保您的请求在重定向发生后将保持原始请求方法。

            【讨论】:

              【解决方案11】:

              我对HTTP和HTTPS不是很了解,所以如果这个答案不是很好,我很抱歉。

              据我了解,即使客户端和(指定客户端的)服务器使用 HTTPS,Request::secure() 也可能返回 false,因为您的应用程序可能在不同的服务器上运行,该服务器可能未收到 https 请求.

              我在 heroku 中托管我的 laravel 应用程序,它似乎就是这样做的。我的猜测是主(客户端指定)服务器是负载平衡器,当请求被转发时,它会作为正常的 HTTP 请求到达另一台服务器。

              当这种转发发生时,您不应该只检查Request::secure() 是否为true。我被指示(#laravel @ irc.freenode.com 中的某个人)还要检查 Request::server('HTTP_X_FORWARDED_PROTO') 以查看它是否等于 'https'

              因此,如果您打算遵循此处的其他建议并在不安全的情况下执行重定向,请尝试检查此服务器参数。

              【讨论】:

              • 你说得对!另外:为什么在应用程序中执行此逻辑,而不是前端服务器配置?
              • @LuisMasuelli 在我的情况下,这是因为 idk 如何正确配置 heroku。当我拥有本地 apache 服务器时,这一切都是通过 apache 的配置完成的。我尚未了解有关使用 heroku 服务的更多信息。
              【解决方案12】:

              对于 laravel 5.1,您应该使用 App\Http\Providers\RouteServiceProvider@boot 中的给定代码

              $router->filter('force.ssl', function () {
                    if ( ! request()->secure() ) {
                         return redirect()->secure(request()->path());
                    }
              });
              

              现在你可以在路由文件中使用它了。

              Route::group(['before' => 'force.ssl'], function () {
                  // Routes here
              });
              

              你也可以在$router-&gt;group()中添加['before' =&gt; 'force.ssl']

              App\Http\Providers\RouteServiceProvider@map
              

              【讨论】:

                【解决方案13】:

                如果在代理后面并且 Request::secure() 不起作用。

                App::before( function( $request )
                {
                  // set the current IP (REMOTE_ADDR) as a trusted proxy
                  Request::setTrustedProxies( [ $request->getClientIp() ] );
                });
                

                【讨论】:

                  【解决方案14】:

                  结合以前的答案来使用 Laravel 4.2 中可用的常量和方法。

                  routes.php

                  Route::when('*', 'secure');
                  

                  filters.php

                  use Illuminate\Http\Response as IlluminateResponse;
                  
                  Route::filter('secure', function ()
                  {
                      if ( ! Request::secure() && Request::getPort() != 443)
                      {
                          return Redirect::secure(
                              Request::path(),
                              in_array(Request::getMethod(), ['POST', 'PUT', 'DELETE'])
                                  ? IlluminateResponse::HTTP_TEMPORARY_REDIRECT
                                  : IlluminateResponse::HTTP_FOUND
                          );
                      }
                  });
                  

                  【讨论】:

                    【解决方案15】:

                    如果您必须使用 Laravel 4 本身来处理重定向(像我一样),我会进行以下设置(解释为代码中的 cmets):

                    路由过滤器:

                    // app/filters.php
                    Route::filter('ssl.force', function()
                    {
                        if(App::environment('production') && !Request::secure())
                        {
                            // don't set a session cookie when redirecting to another scheme to 
                            // avoid dropping the session when switching scheme
                            Config::set('session.driver', 'array');
                            // preserve query string while redirecting by using fullUrl()
                            // instead of Redirect::secure + Request::path()
                            $url = str_replace('http://', 'https://', Request::fullUrl());
                            return Redirect::to($url, 302, array(), true);
                        }
                    
                        // secure cookies for https
                        Config::set('session.secure', Request::secure());
                    });
                    

                    然后将过滤器作为前过滤器应用到您的路由或路由组。 例如:

                    // app/routes.php
                    Route::group(array('before' => 'ssl.force'), function () {
                        // SSL routes
                    });
                    

                    【讨论】:

                      猜你喜欢
                      • 2014-11-17
                      • 2016-10-23
                      • 2016-05-13
                      • 2013-04-06
                      • 2014-06-30
                      • 2018-09-15
                      • 2017-11-05
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多