Laravel从路由生成安全https 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函数,因为默认情况下它会生成绝对

编辑

我真的找不到从路由名称生成安全URL的方法

要获得完整的URL,我使用

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