Laravel将所有请求重定向到HTTPS

时间:2013-11-14 01:24:43

标签: laravel-4

我们的整个网站都将通过https提供服务。我在每条路线都有'https'。但是,如果他们通过http?

尝试将其重定向到https?
Route::group(array('https'), function()
{
     // all of our routes
}

15 个答案:

答案 0 :(得分:94)

使用App ::之前

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

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

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

答案 1 :(得分:33)

另一个答案可能是让您的Web服务器处理此问题。如果您使用的是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本身并不需要处理任何事情。在Web服务器级别处理这样的支票通常会更便宜。

答案 2 :(得分:12)

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

此设置适用于

  • Laravel 5并可能适用于Laravel 3/4
  • 应用程序加载到运行EC2服务器实例的Elastic Beanstalk
  • 用于DNS解析的路由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 。选择协议 HTTPS 。为 SSL证书ID 第2步中选择CERTIFICATE_NAME。保存配置。

  5. 转到控制台。点击 EC2实例。点击加载平衡器。单击负载平衡器。单击实例,然后向下滚动以查看分配给该负载均衡器的EC2实例。如果EC2实例与您的应用程序URL具有相同的名称(或关闭的内容),请记下负载均衡器的 DNS名称。它应采用awseb-e-...

  6. 格式
  7. 返回控制台。点击 CloudFront 。点击创建分配。选择网络分发。

  8. 设置分发。将原始域名设置为您在步骤5 中找到的负载均衡器DNS名称。将查看器协议策略设置为将HTTP重定向到HTTPS 。将转发查询字符串设置为。将备用域名(CNAME)设置为您要用于应用程序的URL。将 SSL证书设置为您在第2步中上传的CERTIFICATE_NAME。创建您的发行版。

  9. 在CloudFront中单击您的分发名称。点击来源,选择您的来源,然后点击修改。确保原始协议政策 匹配查看器。回去。点击行为,选择您的来源,然后点击修改。将转发标题更改为白名单,然后添加主机。保存。

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

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

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

    php artisan make:middleware EB_SSL_Trust
    
  13. 然后将其添加到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网址。

答案 3 :(得分:8)

Laravel 5.1。* 中不推荐使用过滤器。这对于MiddleWare来说是一个完美的工作。

创建一个中间件并在句柄部分输入

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

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

答案 4 :(得分:7)

使用.htaccess Apache进行laravel 4.2.X

原始文件

<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>

答案 5 :(得分:5)

结合以前的答案并更新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');

答案 6 :(得分:3)

如果您想使用https重定向到同一网址,则应使用Request::getRequestUri()代替Request::path()

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

答案 7 :(得分:2)

这在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>

答案 8 :(得分:1)

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

这是一种解决方法:

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

答案 9 :(得分:1)

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

要确保正确重定向POST请求,请使用

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

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

答案 10 :(得分:1)

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

我的理解是存在一个问题,即使客户端和(客户端指定的)服务器使用HTTPS,Request::secure()也可能返回false,因为您的应用程序可能正在另一台服务器上运行,该服务器可能没有接收到https请求。

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

如果发生此类转发,您不应只检查Request::secure()是否为true。我被#laravel @ irc.freenode.com的某人指示也检查Request::server('HTTP_X_FORWARDED_PROTO')以查看它是否等于'https'

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

答案 11 :(得分:1)

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

您还可以在['before' => 'force.ssl']

中添加$router->group()
App\Http\Providers\RouteServiceProvider@map

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

结合以前的答案,使用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
        );
    }
});

答案 14 :(得分:0)

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

路线过滤器:

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