Laravel将所有请求redirect到HTTPS
我们的整个网站将通过https服务。 我在每条路线上都有“https”。 但是,如果他们尝试通过HTTP,我如何将它们redirect到https?
Route::group(array('https'), function() { // all of our routes }
使用App :: before
您可能可以利用app/filters.php
文件中的App::before()
块。
更改块以包括一个简单的检查,看看当前的请求是否安全,如果不是,redirect它。
App::before(function($request) { if( ! Request::secure()) { return Redirect::secure(Request::path()); } });
使用filter
另一种select可能是像这样创build一个filter。 人们通常也将其存储在app/filters.php
。
Route::filter('force.ssl', function() { if( ! Request::secure()) { return Redirect::secure(Request::path()); } });
然后,您可以将这个新filter强制执行到您的任何路由,路由组或控制器。
个人路线
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'); }
另一个答案可能是让你的Web服务器处理这个问题。 如果您使用的是Apache,则可以使用RedirectSSLfunction来确保所有请求都转到您站点的HTTPS版本,并且如果不redirect。 在Laravel甚至得到要求之前,这将会发生。
Apache RedirectSSL
如果你在NGINX上,你可以通过两个服务器块来完成。 一个用于端口80上的正常HTTPS,另一个用于端口443上的HTTPS。然后将普通服务器块configuration为始终redirect到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. }
我个人会select这个选项,因为PHP本身不需要处理任何东西。 在Web服务器级别处理像这样的检查通常更便宜。
对于使用Laravel 4/5和Elastic Beanstalk的用户,使用这些方法强制HTTPS很困难,因为isSecure()
将返回false
。 此外,使用.htaccess
redirect将导致Chrome的redirect循环,并在Firefox中延迟页面加载时间。
这个设置是为了
- Laravel 5并且可能为Laravel 3/4工作
- 加载到运行EC2服务器实例的Elastic Beanstalk上的应用程序
- 路由53用于DNSparsing
- Cloudfront用于所有资产的全球CDN并实施HTTPS
- 我在Windows机器上运行
aws
。 Linux可能略有不同?
经过几个小时的尝试,我设法使用以下步骤将所有HTTP请求转发到HTTPS:
-
获得SSL证书。 指南和提供商很多,可以通过谷歌searchfind。
-
使用
aws
console命令将证书上传到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/
-
创build一个Elastic Beanstalk应用程序。 继续安装过程。 一旦应用程序被设置,进入configuration – > networking层 – > 负载平衡 ,然后点击齿轮图标 。
-
select安全侦听器端口为443 。 selectProtocol作为HTTPS 。 从步骤2中select
CERTIFICATE_NAME
以获取SSL证书ID 。 保存configuration。 -
转到您的控制台 。 点击EC2实例 。 点击负载平衡器 。 点击负载平衡器。 单击实例,然后向下滚动以查看分配给该负载均衡器的EC2实例。 如果EC2实例的名称与您的应用程序URL(或closures的)相同,请记下负载均衡器的DNS名称 。 它应该是格式
awseb-e-...
-
回到你的控制台 。 点击CloudFront 。 点击创build分配 。 select一个Web分配。
-
设置分配。 将您的源域名设置为您在步骤5中find的负载均衡器DNS名称。 将查看器协议策略设置为将HTTPredirect到HTTPS 。 将转发查询string设置为是 。 将备用域名(CNAME)设置为要用于应用程序的URL。 将SSL证书设置为您在步骤2中上传的
CERTIFICATE_NAME
。 创build你的发行版。 -
在CloudFront中点击您的分配名称。 点击来源,select您的来源,然后点击编辑 。 确保您的Origin协议策略是匹配查看器 。 回去。 点击行为 ,select您的来源,然后点击编辑 。 将转发标题更改为白名单并添加主机 。 保存。
-
转到您的控制台 。 点击路线53 。 点击托pipe区域 。 点击创build托pipe区域 。 设置你的域名。 一旦设置,点击创buildlogging集 。 input你的Alogging。 select别名为是 。 您的Alias Target是您的CloudFront分配。 保存logging。
-
为您的域设置名称服务器以指向Route 53名称服务器。 等待一切传播,这可能是几个小时。 转到您的url。 您将被自动redirect到HTTPS。
-
“但是等等,我的链接不去HTTPS!? 您需要处理CloudFront将传递的
X-Forwarded-Proto
标头。 对于Laravel 4,请遵循本指南 。 对于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创build这些链接,请使用secure_asset()
在您的视图中创buildHTTPS URL。
使用.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>
在Laravel 5.1中 , filter的使用已被废弃。 这对MiddleWare来说是一个完美的工作。
创build一个中间件,并在句柄部分放
public function handle($request, Closure $next) { if(! $request->secure()) { return redirect()->secure($request->path()); } return $next($request); }
然后,只需在Kernel.php中注册中间件,并将其用于路由或控制器。
结合以前的答案和更新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');
如果你想redirect到相同的URL,但使用https,你应该使用Request::getRequestUri()
而不是Request::path()
:
App::before(function($request) { if( ! Request::secure()) { return Redirect::secure(Request::getRequestUri()); } });
如果有问题,由于某种原因, 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()); } });
我在执行POST请求时强制ssl有问题。 它总是会redirect到GET。 发生这种情况是因为Redirect::secure()
默认使用302redirect。
为了确保你的POST请求被正确的redirect,使用类似的东西
return Redirect::secure("your/path/here", 307)
这将确保您的请求将在redirect发生后保持原始请求方法。
我不明白HTTP和HTTPS的详细,所以我很抱歉,如果这个答案不是很好。
我的理解是,即使客户端和(客户端指定的)服务器使用HTTPS, Request::secure()
也会返回false,因为您的应用程序可能运行在不同的服务器上,可能不会收到https请求。
我在heroku托pipe我的laravel应用程序,似乎是这样做的。 我的猜测是,主(客户端指定的)服务器是一个负载平衡器,当请求被转发时,它作为一个普通的HTTP请求到达另一个服务器。
当这种转发可能发生时,您不应该只检查Request::secure()
是否为true
。 我被指示(由#laravel @ irc.freenode.com中的某个人)也检查Request::server('HTTP_X_FORWARDED_PROTO')
,看它是否等于'https'
。
因此,如果您打算在此处遵循其他build议,并在不安全的情况下执行redirect,请尝试检查此服务器参数。
对于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->group()
中join['before' => 'force.ssl']
App\Http\Providers\RouteServiceProvider@map
如果在代理和Request :: secure()后面不起作用。
App::before( function( $request ) { // set the current IP (REMOTE_ADDR) as a trusted proxy Request::setTrustedProxies( [ $request->getClientIp() ] ); });
结合以前的答案来使用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 ); } });
如果你必须使用Laravel 4本身来处理redirect(像我一样),我会去下面的设置(解释代码中的注释):
路由filter:
// 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()); });
然后将filter作为之前的filter应用于您的路由或路由组。 例如:
// app/routes.php Route::group(array('before' => 'ssl.force'), function () { // SSL routes });
这在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>
这是Laravel 5.2.x或更高版本的备用解决scheme。