Laravel 5 - 重定向到HTTPS

Nig*_*ICU 107 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());
    }
});
Run Code Online (Sandbox Code Playgroud)

我认为中间件应该在这样的地方实现,但我不能完全理解这一点.

谢谢!

UPDATE

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

man*_*nix 226

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

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); 
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,将此中间件应用于每个请求添加在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'       

];
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,如果出现以下情况,中间件会将每个请求重定向到https:

  1. 当前请求没有安全协议(http)
  2. 如果你的环境等于production.因此,只需根据您的喜好调整设置即可.

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() ] ); 
Run Code Online (Sandbox Code Playgroud)

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

编辑27/09/2016 - 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

    ],
];
Run Code Online (Sandbox Code Playgroud)

请记住,web默认情况下,组应用于每个路由,因此您无需web在路由或控制器中明确设置.

编辑23/08/2018 - Laravel v5.7

  • 根据您可以使用的环境重定向请求App::environment() === 'production'.对于以前的版本是 env('APP_ENV') === 'production'.
  • 使用\URL::forceScheme('https');实际上不重定向.它只是在https://呈现网站时构建链接.

  • 很好的答案!只有一个细节:最好使用301重定向向Google表明这是一个永久性的运动.例如:`return redirect() - > secure($ request-> getRequestUri(),301);` (7认同)
  • 对于那些在负载均衡器或代理下的人可以更改为secure()到`$ request-> server('HTTP_X_FORWARDED_PROTO')!='https'`这对我有用 (4认同)
  • 这似乎给了我一个重定向循环......但看起来它应该可行.我不知道它是否有任何区别,但我们正在使用Cloudflare SSL.但我认为这不会改变简单的重定向. (3认同)
  • @NightMICU我不确定你是否已经解决了重定向的问题,但这可能是由Cloudflare传递的标题引起的.CloudFlare可能通过HTTP命中您的服务器并传递X-Forwarded-Proto标头,声明它正在转发HTTPS请求.您需要在中间件中添加另一行"$ request-> setTrustedProxies([$ request-> getClientIp()]);"以信任CloudFlare正在发送的标头.这将停止重定向循环. (2认同)
  • @manix太棒了.本周末刚刚通过我自己的项目完成了这个HTTPS问题 - 这些小东西会让你沮丧几个小时! (2认同)

小智 53

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

\URL::forceScheme('https');
Run Code Online (Sandbox Code Playgroud)

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

  • 嘿,刚刚通过谷歌搜索发现 - 注意在5.4中它是`\ URL :: forceScheme('https');` (14认同)
  • 我很确定这只是用于构建链接.这不会强迫用户https,它只会提供前缀为https://的链接 (14认同)
  • 在同一个文件中,你也可以做`if($ this-> app-> environment()==='production'){$ this-> app ['request'] - > server-> set('HTTPS' ,true); }` (2认同)
  • 你的意思是\ URL :: forceScheme('https')` (2认同)

Ass*_* Ch 29

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

RewriteEngine On

RewriteCond %{HTTPS} !on
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Run Code Online (Sandbox Code Playgroud)

  • @Dan - 是的,但是你仍然需要为舞台本地设置它(如果开发人员在本地开发中使用不同的URL,这会更复杂,例如.dev,.local,subdomains,...等).我宁愿在应用程序中使用那种逻辑. (3认同)
  • 如果您有多个环境(开发,阶段,生产),那么这比在所有环境上设置SSL都不好。 (2认同)

小智 16

对于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');
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 只是为了澄清:1)这些更改应该在app/Providers/AppServiceProvider.php中完成; 2)这只是为了设置应用程序内部生成的链接使用SSL,它不会强制您使用SSL (12认同)

Mla*_*vic 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);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 7

这适用于Larave 5.2.x及更高版本.如果您想要通过HTTPS提供一些内容以及通过HTTP提供其他内容,这里有一个适合我的解决方案.您可能想知道,为什么有人想通过HTTPS只提供一些内容?为什么不通过HTTPS提供服务?

虽然通过HTTPS服务整个站点完全没问题,但通过HTTPS切断所有内容会对服务器产生额外的开销.记住加密并不便宜.轻微的开销也会对您的应用响应时间产生影响.你可以说商品硬件价格便宜且影响可以忽略不计但是我离题:)我不喜欢用https来提供图片等营销内容大页面的想法.所以这就是它.它与上面使用中间件的建议类似,但它是一个完整的解决方案,允许您在HTTP/HTTPS之间来回切换.

首先创建一个中间件.

php artisan make:middleware ForceSSL
Run Code Online (Sandbox Code Playgroud)

这就是您的中间件应该是什么样子.

<?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);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我不是基于环境进行过滤,因为我为本地开发和生产都设置了HTTPS,因此不需要.

以下内容添加到您的routeMiddleware \软件\ 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,
];
Run Code Online (Sandbox Code Playgroud)

接下来,我想确保两个基本组登录/注册等以及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
});
Run Code Online (Sandbox Code Playgroud)

确认您的中间件已从控制台正确应用于您的路由.

php artisan route:list
Run Code Online (Sandbox Code Playgroud)

现在你已经获得所有的表格或应用程序的敏感区域,现在的关键是使用你的视图模板来定义您的安全和公众(非HTTPS)的链接.

根据上面的示例,您将如下呈现您的安全链接 -

<a href="{{secure_url('/login')}}">Login</a>
<a href="{{secure_url('/signup')}}">SignUp</a>
Run Code Online (Sandbox Code Playgroud)

非安全链接可以呈现为

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

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

如果你不渲染以http完全合格的URL,并使用相对链接URL("/关于我们"),则用户访问安全站点后,HTTPS将仍然存在.

希望这可以帮助!


Mau*_*ani 6

仅使用.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>
Run Code Online (Sandbox Code Playgroud)

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


Quy*_* Le 5

您可以使用RewriteRule将.htaccess中的ssl强制与index.php放在同一文件夹中。
请添加为图片附件,在所有其他规则之前添加 设置ssl .htaccess


all*_*y4v 5

在 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;
}
Run Code Online (Sandbox Code Playgroud)

注意:使用forceSchema, NOTforceScheme