Laravel 5 – redirect到HTTPS

在我的第一个Laravel 5项目上工作,不知道在哪里或如何放置逻辑来强制HTTPS在我的应用程序。 这里最重要的是,有很多指向应用程序的域,只有三个使用SSL(第三个域是一个后备域,长话短说)。 所以我想在我的应用程序的逻辑而不是.htaccess中处理这个。

在Laravel 4.2中,我用位于filters.php中的代码完成了redirect:

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

我正在考虑中间件是这样的东西应该实施,但我不能完全弄清楚使用它。

谢谢!

UPDATE

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

你可以使它与中间件类一起工作。 让我给你一个想法。

 namespace MyApp\Http\Middleware; use Closure; class HttpsProtocol { public function handle($request, Closure $next) { if (!$request->secure() && env('APP_ENV') === 'prod') { 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' ]; 

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

  1. 目前的请求没有安全协议(http)
  2. 如果你的环境等于prod 。 所以,请根据您的喜好调整设置。

CloudFlare的

我正在使用WildCard SSL在生产环境中使用此代码,并且代码正常工作。 如果我删除&& env('APP_ENV') === 'prod'并在localhost中testing它,redirect也可以。 所以,有没有安装SSL不是问题。 看起来你需要非常注意你的Cloudflare层,以便redirect到Https协议。

编辑23/03/2015

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

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

…信任CloudFlare发送的标头。 这将停止redirect循环

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

只需要在kernel.php file web组中添加中间件类:

 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

另一个选项对我来说很有用,在AppServiceProvider中将这些代码放在引导方法中:

 \URL::forceScheme('https'); 

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

对于laravel 5.4使用这种格式来获得httpsredirect而不是.htaccess

 namespace App\Providers; use Illuminate\Support\Facades\URL; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { public function boot() { URL::forceScheme('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()]); if (!$request->isSecure()) { return redirect()->secure($request->getRequestUri()); } } return $next($request); } } 

这是Larave 5.2.x和更高版本。 如果你想有一个选项来通过HTTPS提供一些内容,而通过HTTP的其他内容则是一个适合我的解决scheme。 您可能会想,为什么有人只想通过HTTPS提供一些内容? 为什么不通过HTTPS提供服务?

尽pipe通过HTTPS服务整个站点是完全正确的,但是通过HTTPS切断所有内容还会在服务器上产生额外的开销。 记住encryption不会便宜。 轻微的开销也会影响您的应用程序响应时间。 你可以争辩说,商品硬件便宜,影响是微不足道的,但我离题:)我不喜欢通过https服务的图像等营销内容大网页的想法。 所以在这里。 这与其他人使用中间件时所build议的类似,但它是一个完整的解决scheme,可以在HTTP / HTTPS之间来回切换。

首先创build一个中间件。

 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中,以便您可以select和select哪个路由组应该强制使用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, ]; 

接下来,我想确保两个基本组login/注册等,以及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 / login和http:// yourhost / aboutus

如果您不使用http呈现完全限定的URL并使用相对链接url('/ aboutus'),则在用户访问安全网站后,https将持续存在。

希望这可以帮助!

在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每个redirect将转到url https和http请求我们需要一次redirect,所以在IndexController.php只是我们需要做一次redirect

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

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

刚刚使用.htaccess文件来实现httpsredirect? 这应该放在项目根目录(不在公用文件夹中)。 您的服务器需要configuration为指向项目根目录。

 <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(写这个答案的最新版本),但它应该继续工作的function版本,即使laravel改变或删除一些function。