我们的整个网站将通过 https 提供服务。我在每条路线中都有“https”。但是,如果他们通过 http 进行尝试,我如何将他们重定向到 https?
Route::group(array('https'), function()
{
// all of our routes
}
我们的整个网站将通过 https 提供服务。我在每条路线中都有“https”。但是,如果他们通过 http 进行尝试,我如何将他们重定向到 https?
Route::group(array('https'), function()
{
// all of our routes
}
使用 App::before
您也许可以利用文件中的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');
}
另一个答案可能是让您的网络服务器处理这个问题。如果您使用的是 Apache,您可以使用 RedirectSSL 功能来确保所有请求都转到您网站的 HTTPS 版本,如果没有重定向它们。这将在 Laravel 收到请求之前发生。
如果你在 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 服务器级别处理这样的检查通常更便宜。
对于使用 Laravel 4/5 和 Elastic Beanstalk 的用户,使用这些方法很难强制使用 HTTPS,因为isSecure()
会返回false
. 此外,使用.htaccess
重定向将导致 Chrome 出现重定向循环并延迟 Firefox 中的页面加载时间。
此设置适用于
aws
在 Windows 机器上运行。Linux 可能略有不同?经过我自己几个小时的尝试,我设法使用以下步骤将所有 HTTP 请求转发到 HTTPS:
获取 SSL 证书。指南和提供者众多,可以通过 Google 搜索找到。
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/
创建一个 Elastic Beanstalk 应用程序。继续完成设置过程。设置应用程序后,转到配置->网络层->负载平衡,然后单击齿轮图标。
选择Secure listener port作为443。选择协议作为HTTPS。CERTIFICATE_NAME
从步骤 2中选择SSL证书 ID。保存配置。
转到您的控制台。单击EC2 实例。单击负载均衡器。单击负载均衡器。单击实例并向下滚动以查看分配给该负载均衡器的 EC2 实例。如果 EC2 实例与您的应用程序 URL 具有相同的名称(或类似名称),请记下负载均衡器的DNS 名称。它应该是格式awseb-e-...
返回到您的控制台。单击CloudFront。单击创建分配。选择一个Web分发。
设置分布。将您的Origin Domain Name设置为您在步骤 5中找到的负载均衡器 DNS 名称。将查看器协议策略设置为将 HTTP 重定向到 HTTPS。将转发查询字符串设置为Yes。将备用域名 (CNAME)设置为要用于应用程序的 URL。将SSL 证书设置为您在步骤 2CERTIFICATE_NAME
中上传的证书。创建您的发行版。
在 CloudFront 中单击您的分配名称。单击Origins,选择您的来源,然后单击Edit。确保您的Origin Protocol Policy是Match Viewer。回去。单击Behaviors,选择您的来源,然后单击Edit。将Forward Headers更改为Whitelist并添加Host。节省。
转到您的控制台。单击53 号公路。单击托管区域。单击创建托管区域。设置您的域名。设置完成后,单击Create Record Set。输入您的 A 记录。选择别名为是。您的别名目标是您的 CloudFront 分配。保存记录。
为您的域设置名称服务器以指向 Route 53 名称服务器。等待一切传播,这可能需要几个小时。转到您的网址。您将被自动重定向到 HTTPS。
“但是等等,我的链接没有转到 HTTPS!?” 您需要处理X-Forwarded-Proto
CloudFront 将传递的标头。对于 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 创建这些链接,请使用secure_asset()
在您的视图中创建 HTTPS URL。
Laravel 5.1.*已弃用过滤器。对于 MiddleWare 来说,这是一项完美的工作。
创建一个中间件并在句柄部分放置
public function handle($request, Closure $next)
{
if(! $request->secure()) {
return redirect()->secure($request->path());
}
return $next($request);
}
然后只需在您的 Kernel.php 中注册您的中间件并将其与您的路由或控制器一起使用。
在 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>
结合以前的答案并更新 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');
如果你想重定向到相同的 URL 但使用 https,你应该使用Request::getRequestUri()
而不是Request::path()
:
App::before(function($request)
{
if( ! Request::secure())
{
return Redirect::secure(Request::getRequestUri());
}
});
这在 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>
如果您遇到问题,由于某种原因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 的问题。它总是会重定向到 GET。发生这种情况Redirect::secure()
是因为默认情况下使用 302 重定向。
为确保您的 POST 请求被正确重定向,请使用类似
return Redirect::secure("your/path/here", 307)
这将确保您的请求在重定向发生后将保持原始请求方法。
我不太了解 HTTP 和 HTTPS,所以如果这个答案不是很好,我很抱歉。
据我了解,即使客户端和(客户端指定的)服务器使用 HTTPS,Request::secure()
也可能返回 false,因为您的应用程序可能在不同的服务器上运行,该服务器可能没有收到 https 请求。
我在 heroku 中托管我的 laravel 应用程序,它似乎就是这样做的。我的猜测是主(客户端指定)服务器是负载平衡器,当请求被转发时,它会作为正常的 HTTP 请求到达另一台服务器。
当这种转发可能发生时,您不应该只检查Request::secure()
to true
。我被指示(#laravel @ irc.freenode.com 中的某个人)还要检查Request::server('HTTP_X_FORWARDED_PROTO')
它是否等于'https'
.
因此,如果您打算遵循此处的其他建议并在不安全的情况下执行重定向,请尝试检查此服务器参数。
对于 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
如果在代理后面并且 Request::secure() 不起作用。
App::before( function( $request )
{
// set the current IP (REMOTE_ADDR) as a trusted proxy
Request::setTrustedProxies( [ $request->getClientIp() ] );
});
结合以前的答案来使用 Laravel 4.2 中可用的常量和方法。
路由.php
Route::when('*', 'secure');
过滤器.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 本身来处理重定向(像我一样),我会进行以下设置(解释为代码中的注释):
路由过滤器:
// 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
});