Laravel从路由生成安全https URL
编辑 我真的找不到从路由名称生成安全URL的方法 要获得完整的URL,我使用Laravel从路由生成安全https URL,url,laravel,https,routing,Url,Laravel,Https,Routing,编辑 我真的找不到从路由名称生成安全URL的方法 要获得完整的URL,我使用 echo route('my_route_name'); 但是,如果我想要一个带有https的URL,该怎么办呢?我认为只有一种方法可以做到这一点 要生成命名路由的安全URL,您可能需要将路由传递到secure\u URLhelper函数中 secure_url(URL::route('your_route_name', [], false)); 您不能真正使用routehelper函数,因为默认情况下它会生成绝对
echo route('my_route_name');
但是,如果我想要一个带有https的URL,该怎么办呢?我认为只有一种方法可以做到这一点 要生成命名路由的安全URL,您可能需要将路由传递到
secure\u URL
helper函数中
secure_url(URL::route('your_route_name', [], false));
您不能真正使用
route
helper函数,因为默认情况下它会生成绝对URL(使用http://
),并且它是http
而不是您想要的https
版本,以供将来的访问者参考:
secure_url函数无法正确处理GET参数。因此,例如,如果要将用户访问过的url转换为安全url,同时保留GET字段,则需要使用:
secure_url(Request::path()).'?'.http_build_query(Input::all());
特别要注意使用path()而不是url()——如果你给它一个完整的url,它不会在一开始就替换http,使它实际上毫无用处。事实证明,laravel并不关心url是否安全,因为它是基于当前url生成的。如果您在https页面上,
route()
将返回安全url。如果在http上,则http://
url
问题是,Laravel没有检测到启用了https,这是由于错误的服务器配置造成的
您可以通过调用Request::isSecure()检查Laravel是否将当前连接视为https代码>要生成安全(https)路由,请使用以下名为“auth”的内置“before”筛选器:
例如:
Route::get('your-route', ['before' => 'auth', 'uses' => YourController@yourAction']);
现在,当您输出链接时,它将以“https”作为前缀。Laravel 5.x将通过route()helper生成安全URL,如果它检测到传入连接是安全的。如果应用程序隐藏在负载平衡器或代理(例如Cloudflare)后面,则通常会出现问题,因为应用程序服务器和负载平衡器/代理之间的连接可能不安全
我现在正在使用Laravel Forge+Cloudflare,这是我能找到的最简单的方法,可以让我认为传入连接是安全的(不确定是否有其他代理)
生成自签名证书(请参阅或)
在Forge面板中,通过站点>您的站点>SSL证书>安装现有证书插入您的私钥和证书
激活
在CloudFlare面板中,Crypto>SSL
,选择“完整”(不严格)
完成(传播更改需要几分钟)
简而言之,客户端和Cloudflare之间的连接由Cloudflare自己的SSL保护。app server和Cloudflare之间的连接通过您生成的证书得到保护(因此应用程序将“连接”视为安全的)
您可以对其他堆栈应用相同的原则。更新:如评论中所指出的,一种更简单的方法是为4.2-5.3或URL::forceSchema('https')之间的Laravel版本添加URL::forceSchema('https');
在AppServiceProvider
文件的boot
方法中,为版本5.4+
旧答案:
这实际上是完全可能的,并且只需要一行代码就可以完成
Laravel本身不检查SSL的存在,这取决于Symfony。我们的关键在于让它相信当前请求是安全的
问题是,我们必须将HTTPS
服务器参数设置为true,最简单的方法是将以下代码粘贴到AppServiceProvider的boot
方法中:
$this->app['request']->server->set('HTTPS', true);
在我的情况下,我只需要在生产环境中强制SSL,本地环境仍应在http上工作。这就是我仅在生产环境中强制SSL的方式:
$this->app['request']->server->set('HTTPS', $this->app->environment() != 'local');
顺便说一句,记住这些术语,您将来可能需要它们。将其放在filters.php文件中,随处都将被强制使用https,同时保留URL参数:
//force ssl
App::before(function () {
if(!Request::secure() && App::environment() != 'local')
{
$baseHost = Request::getHttpHost();
$requestUri = Request::getRequestUri();
$newLink = 'https://'.$baseHost.$requestUri;
return Redirect::to($newLink);
}});
我在尝试使用Laravel5.4在Blade中生成路线作为表单操作时遇到了这个问题。
然后我偶然发现了secure_url(),所以我试了一下
{{ secure_url(route('routename', $args)) }}
这仍然返回了一个不安全的URL:-(
在深入研究代码并添加一些调试日志之后,我最终发现,如果传入的url参数已经是绝对url(包括方案),则secure_url不会更改该参数
幸运的是,route有一个absolute标志作为第三个参数,如果$absolute作为false传递,则返回一个相对URL
假设/a/{id}/b是命名路由“a.b”
加入我所达到的两个目标:
{{ secure_url(route('routename', $args, false)) }}
正如预期的那样,它产生了
:-)使用安全url:
secure_url(URL::route('your_route_name', [], false));
您需要将URL::route设置为false才能不返回完整的URL。然后使用secure_URL函数生成指向给定路径的完全限定HTTPS URL
从UrlGenerator界面可以使用URL::route
在大多数情况下,应使用站点加载的相同方案生成路由。Laravel会自动检测请求是否具有X-Forwarded-Proto
标头,并使用它来决定在生成的路由URL中使用哪个方案。如果站点位于反向代理之后,则应将反向代理IP地址添加到受信任的URL列表中proxies.package有助于实现这一点。它位于Laravel 5.5中。例如,我的config/trustedproxy.php
如下所示:
<?php
return [
'proxies' => '*',
'headers' => [
]
];
用您的域替换example.com
。SSL证书由提供。正如我在a中提到的,我找到了5种生成安全URL的方法
将web服务器配置为将所有非安全请求重定向到https。nginx配置示例:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
使用https设置环境变量APP\u URL
:
APP_URL=https://example.com
使用辅助工具(Laravel5.6)
将以下字符串添加到AppServiceProvider::boot()方法(适用于5.4+版本):
路由组隐式设置方案(Lara)
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/example.com_access.log;
error_log /var/log/nginx/example.com_error.log;
client_max_body_size 50m;
location / {
proxy_pass http://localhost:8002;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
APP_URL=https://example.com
\Illuminate\Support\Facades\URL::forceScheme('https');
Route::group(['scheme' => 'https'], function () {
// Route::get(...)->name(...);
});
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
\URL::forceRootUrl(\Config::get('app.url'));
if (str_contains(\Config::get('app.url'), 'https://')) {
\URL::forceScheme('https');
}
}
echo url()->secure('my_route_name');
APP_URL=https://example.com
{{ URL::route('my.route', params) }}
{{ route('my.route', params) }}
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
APP_URL=https://example.com