Laravel 从路由生成安全的 https URL

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24426423/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 02:52:00  来源:igfitidea点击:

Laravel generate secure https URL from route

urllaravelhttpsrouting

提问by Mārti?? Briedis

Edit

编辑

I can't really find a way to generate a secure URL from route name.

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

To get a full URL, I use

要获得完整的 URL,我使用

echo route('my_route_name');

But what to do, if I want a URL with https?

但是,如果我想要一个带有 https 的 URL,该怎么办?

采纳答案by Mārti?? Briedis

Actually turns out, that laravel doesn't care if url is secure or not, because it generates based on the current url. If you're on https page, route()will return secure url. If on http, then http://url

事实上,laravel 并不关心 url 是否安全,因为它是根据当前 url 生成的。如果您在 https 页面上,route()将返回安全 url。如果在 http 上,http://则为 url

The problem was, that Laravel didn't detect that https was enabled, which was due to faulty server configuration.

问题是,Laravel 没有检测到 https 已启用,这是由于服务器配置错误造成的。

You can check if Laravel sees the current connection as https by calling Request::isSecure();

您可以通过调用来检查 Laravel 是否将当前连接视为 https Request::isSecure();

回答by Ionut Bajescu

UPDATE:As pointed out in the comments, a simpler way of doing this would be adding URL::forceSchema('https');for Laravel version between 4.2-5.3 or URL::forceScheme('https');for version 5.4+ in the bootmethod of your AppServiceProviderfile.

更新:正如评论中所指出的,一种更简单的方法是在文件的方法中URL::forceSchema('https');为 4.2-5.3 之间的 LaravelURL::forceScheme('https');版本或 5.4+ 版本添加。bootAppServiceProvider

Old answer:

旧答案:

It's actually entirely possible and there's only one line of code needed to accomplish that.

这实际上是完全可能的,并且只需要一行代码即可完成。

Laravel doesn't check the presence of SSL by itself, it depends on Symfony. And there goes our key to making it believe that the current request is secure.

Laravel 本身不会检查 SSL 的存在,它取决于 Symfony。我们的关键是让它相信当前的请求是安全的。

The thing is, we have to set the HTTPSserver paramto true and the easiest method is to paste the following code in the bootmethod of your AppServiceProvider:

问题是,我们必须将 设置HTTPSserver param为 true,最简单的方法是将以下代码粘贴到boot您的方法中AppServiceProvider

$this->app['request']->server->set('HTTPS', true);

In my very case, I only need to force SSL in production, the local env should still work on http. This is how I force SSL only on production:

就我而言,我只需要在生产中强制使用 SSL,本地 env 应该仍然可以在 http 上工作。这就是我仅在生产中强制使用 SSL 的方式:

$this->app['request']->server->set('HTTPS', $this->app->environment() != 'local');

By the way, mind those terms, you may need them in the future.

顺便说一句,请注意这些条款,您将来可能需要它们。

回答by Mārti?? Briedis

I think there is only one way to do this.

我认为只有一种方法可以做到这一点。

To generate the secure URL to your named routes, you might want to pass in your route into the secure_urlhelper function.

要生成命名路由的安全 URL,您可能希望将路由传递到secure_url辅助函数中。

secure_url(URL::route('your_route_name', [], false));

You can't really use the routehelper function because it generates absolute URL (with http://) by default and it's httpnot the httpsversion that you wanted

你不能真正使用route辅助函数,因为它http://默认生成绝对 URL (with ) 并且它http不是https你想要的版本

回答by Aditya

Laravel 5.x will generate secure URL via route() helper if it detects the incoming connection is secure. Problem usually happen if the app is hidden behind load balancer or proxy (e.g. Cloudflare) since the connection between app server and load balancer/proxy might not be secure.

如果 Laravel 5.x 检测到传入连接是安全的,它将通过 route() 助手生成安全 URL。如果应用程序隐藏在负载均衡器或代理(例如 Cloudflare)之后,通常会发生问题,因为应用程序服务器和负载均衡器/代理之间的连接可能不安全。

I am using Laravel Forge + Cloudflare now and this is the easiest way I could find to enable app thinking incoming connection is secure (not sure about other proxy).

我现在正在使用 Laravel Forge + Cloudflare,这是我能找到的最简单的方法来启用应用程序认为传入连接是安全的(不确定其他代理)。

  1. Generate self signed certificate (see https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrsor http://www.selfsignedcertificate.com/)

  2. In Forge panel, insert your private key and cert via Sites > your-site > SSL Certificates > Install Existing Certificate.

  3. Activate

  4. In CloudFlare panel, Crypto > SSL, choose “Full” (not strict)

  5. Done (it will take few minutes for the change to get propagated)
  1. 生成自签名证书(参见https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrshttp://www.selfsignedcertificate.com/)

  2. 在 Forge 面板中,通过Sites > your-site > SSL Certificates > Install Existing Certificate.

  3. 启用

  4. 在 CloudFlare 面板中Crypto > SSL,选择“Full”(不严格)

  5. 完成(更改需要几分钟才能传播)

In short, connection between client and Cloudflare is secured by Cloudflare's own SSL. Connection between app server and Cloudflare is protected via your generated cert (thus the app is seeing 'connection' as secure.

简而言之,客户端和 Cloudflare 之间的连接由 Cloudflare 自己的 SSL 保护。应用服务器和 Cloudflare 之间的连接通过您生成的证书进行保护(因此应用将“连接”视为安全。

You can apply the same principle with other stacks.

您可以将相同的原理应用于其他堆栈。

回答by Prisacari Dmitrii

As I mentioned in a relevant question, I found 5 ways of how to generate secure URLs.

正如我在相关问题中提到的,我找到了 5 种生成安全 URL 的方法。

  1. Configure your web server to redirect all non-secure requests to https. Example of a nginx config:

    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name example.com www.example.com;
        return 301 https://example.com$request_uri;
    }
    
  2. Set your environment variable APP_URLusing https:

    APP_URL=https://example.com
    
  3. Use helper secure_url()(Laravel5.6)

  4. Add following string to AppServiceProvider::boot() method (for version 5.4+):

    \Illuminate\Support\Facades\URL::forceScheme('https');
    
  5. Implicitly set scheme for route group (Laravel5.6):

    Route::group(['scheme' => 'https'], function () {
        // Route::get(...)->name(...);
    });
    

    At the moment this way is not documented, but it works well.

  1. 配置您的 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;
    }
    
  2. APP_URL使用 https设置环境变量:

    APP_URL=https://example.com
    
  3. 使用助手secure_url()(Laravel5.6)

  4. 将以下字符串添加到 AppServiceProvider::boot() 方法(适用于 5.4+ 版本):

    \Illuminate\Support\Facades\URL::forceScheme('https');
    
  5. 路由组隐式设置方案(Laravel5.6):

    Route::group(['scheme' => 'https'], function () {
        // Route::get(...)->name(...);
    });
    

    目前这种方式没有记录,但效果很好。

回答by mixel

In most cases routes should be generated with the same scheme your site was loaded with. Laravel automatically detects if request has X-Forwarded-Protoheader and uses it to decide which scheme to use in generated route URLs. If your site is behind reverse proxy then you should add reverse proxy IP address to list of trusted proxies. https://github.com/fideloper/TrustedProxypackage helps to do this. It's includedin Laravel 5.5. For example, my config/trustedproxy.phplooks like:

在大多数情况下,应该使用与您的站点加载相同的方案来生成路由。Laravel 会自动检测请求是否有X-Forwarded-Proto标头,并使用它来决定在生成的路由 URL 中使用哪种方案。如果您的站点位于反向代理之后,那么您应该将反向代理 IP 地址添加到受信任代理列表中。https://github.com/fideloper/TrustedProxy包有助于做到这一点。它包含在 Laravel 5.5 中。例如,我的config/trustedproxy.php样子:

<?php

return [
    'proxies' => '*',

    'headers' => [
    ]
];

I use it with nginx reverse proxy that has the following configuration:

我将它与具有以下配置的 nginx 反向代理一起使用:

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;
  }
}

Replace example.comwith your domain. SSL certificates was provided by Let's Encryptwith certbot.

替换example.com为您的域。SSL 证书由Let's Encryptcertbot 提供

回答by PHPGrandMaster

Use secure_url:

使用secure_url:

secure_url(URL::route('your_route_name', [], false));

You will need to set URL::route to false in order to not return a full URL. Then use secure_url function generates a fully qualified HTTPS URL to the given path.

您需要将 URL::route 设置为 false 才能不返回完整的 URL。然后使用 secure_url 函数生成到给定路径的完全限定的 HTTPS URL。

From the UrlGenerator interface you can use URL::route

从 UrlGenerator 界面,您可以使用 URL::route

string route(string $name, mixed $parameters = array(), bool $absolute = true)

Get the URL to a named route.
Parameters
string  $name   
mixed   $parameters     
bool    $absolute   
Return Value
string

https://laravel.com/api/5.4/Illuminate/Contracts/Routing/UrlGenerator.html

https://laravel.com/api/5.4/Illuminate/Contracts/Routing/UrlGenerator.html

回答by Joesel T Duazo

On laravel 5.5.* You only need to add https on your .env file as AppServiceProvider already had function that checks if your APP_URL or app.url on your config has https on it.

在 Laravel 5.5.* 上,您只需要在 .env 文件中添加 https,因为 AppServiceProvider 已经具有检查配置中的 APP_URL 或 app.url 是否包含 https 的功能。

class AppServiceProvider extends ServiceProvider
{
 public function boot()
 {

    \URL::forceRootUrl(\Config::get('app.url'));    
    if (str_contains(\Config::get('app.url'), 'https://')) {
        \URL::forceScheme('https');
    }
 }

回答by Samuel Bié

This is certainly old, but someone like me will dump over here one day.

这当然是旧的,但总有一天像我这样的人会在这里倾倒。

In your .env file define the APP_URL to use https instead of using http. Because all laravel url are generated based on this variable.

在您的 .env 文件中定义 APP_URL 以使用 https 而不是使用 http。因为所有的laravel url 都是基于这个变量生成的。

    APP_URL=https://example.com

and wherever you want you can just say

无论你想要什么,你都可以说

{{ URL::route('my.route', params) }}

Or

或者

{{ route('my.route', params) }}

With make sure all the routes are generated with secure protocol, add in the boot method of AppServiceProvider class:

确保所有路由都是使用安全协议生成的,在 AppServiceProvider 类的 boot 方法中添加:

<?php

namespace App\Providers;

use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot(UrlGenerator $url)
    {
        if (config('app.production')) {
            $url->forceScheme('https');
        }
    }


回答by 79man

I came across this issue while trying to generate a route as form action in Blade using Laravel 5.4. Then I hit upon secure_url(), so I tried

我在尝试使用 Laravel 5.4 在 Blade 中生成路线作为表单动作时遇到了这个问题。然后我遇到了secure_url(),所以我尝试了

{{ secure_url(route('routename', $args)) }} 

This still returned a non-secure URL. :-(

这仍然返回了一个不安全的 URL。:-(

After digging through the code and adding some debug logs, I finally figured out that secure_url does not change the incoming url argument, if it's already an absolute URL (including the scheme).

在深入研究代码并添加了一些调试日志后,我终于发现 secure_url 不会更改传入的 url 参数,如果它已经是绝对 URL(包括方案)。

Fortunately route has an absolute flag as the third argument, and returns a relative URL if $absolute is passed as false.

幸运的是 route 有一个绝对标志作为第三个参数,如果 $absolute 被传递为 false 则返回一个相对 URL。

Assuming /a/{id}/b is a named route "a.b"

假设 /a/{id}/b 是一个命名路由“ab”

route('a.b', 1)        : will return http://[domain]/a/1/b 
route('a.b', 1, false) : will return /a/1/b

Joining the two I arrived at :

加入我到达的两个:

{{ secure_url(route('routename', $args, false)) }}

As expected it generated https://[domain]/routeXXX

正如预期的那样,它生成了https://[domain]/routeXXX

:-)

:-)