模仿Apache';用PHP实现ProxyPassReverse 问题摘要

模仿Apache';用PHP实现ProxyPassReverse 问题摘要,php,laravel,authentication,proxy,Php,Laravel,Authentication,Proxy,假设您运行一台服务器,并且希望仅为使用用户名和密码登录的用户(经过身份验证的用户)提供本地主机应用程序中的内容 该应用程序在您的服务器上运行,但不向公众公开。它仅在您的服务器上通过提供 为简单起见,假设您是这样运行localhost应用程序的: cd my-private-folder python3 -m http.server 3838 经过身份验证的用户应该能够转到以查看 本地主机应用程序提供的内容 未经验证的用户应被拒绝访问并重定向到登录页面 问题 Apache有一个指令ProxyP

假设您运行一台服务器,并且希望仅为使用用户名和密码登录的用户(经过身份验证的用户)提供本地主机应用程序中的内容

该应用程序在您的服务器上运行,但不向公众公开。它仅在您的服务器上通过提供

为简单起见,假设您是这样运行localhost应用程序的:

cd my-private-folder
python3 -m http.server 3838
经过身份验证的用户应该能够转到以查看 本地主机应用程序提供的内容

未经验证的用户应被拒绝访问并重定向到登录页面

问题
  • Apache有一个指令
    ProxyPass
    ,它在请求发送到目标之前修改请求中的HTTP头。它还有一个指令
    ProxyPassReverse
    ,在返回用户之前修改响应中的标题

  • 有没有办法在PHP中模仿Apache的行为

  • 有没有一种简单的方法可以在PHP框架中实现这一点

作为参考,有一个名为的包在Go中实现了这个目标。我不知道有哪种等效的PHP软件包


尝试1失败:正在使用路由 以下是我在Laravel 5.5上的尝试:

# /var/www/example.com/routes/web.php
Route::get('/app', function() {
    return Response::make(
        file_get_contents("http://localhost:3838/")
    );
});
# This does not work, because the HTTP header is not modified.
Route::get('/app/{any}', function($any) {
    return Response::make(
        file_get_contents("http://localhost:3838/$any")
    );
})->where('any', '.*');
这将成功地将内容从
localhost:3838
传递到
example.com/app
,但由于未修改HTTP头,因此无法传递应用程序请求的任何资源

例如:

  • localhost应用程序使用Javascript请求
    /resource.jpg

  • 我希望资源从传递到

  • 相反,应用程序发出一个失败的请求以获取

要了解失败的原因,请参阅下面正确运行的Apache解决方案。Apache有一个名为的指令,该指令修改HTTP头,因此localhost应用程序从正确的URL请求资源


使用Apache Apache工作得很好!但是,添加新用户需要在服务器上运行
htpasswd
命令

有了Laravel,新用户应该能够自己在网站上注册

如果没有Laravel,您可以使用Apache保护应用程序,如下所示:

# /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
  ServerName example.com
  Redirect /app /app/
  ProxyPass /app/ http://localhost:3838/
  ProxyPassReverse /app/ http://localhost:3838/
  ProxyPreserveHost On
  <Location /app/>
      AuthType Basic
      AuthName "Restricted Access - Please Authenticate"
      AuthUserFile /etc/httpd/htpasswd.users
      Require user myusername 
      # To add a new user: htpasswd /etc/httpd/htpasswd.users newuser 
  </Location>
</VirtualHost>
#/etc/apache2/sites available/example.com.conf
ServerName example.com
重定向/app/app/
ProxyPass/应用程序/http://localhost:3838/
ProxyPassReverse/应用程序/http://localhost:3838/
代理主机
AuthType Basic
AuthName“受限访问-请验证”
AuthUserFile/etc/httpd/htpasswd.users
需要用户myusername
#添加新用户的步骤:htpasswd/etc/httpd/htpasswd.users newuser
这个相关的回答帮助我更好地理解了
ProxyPassReverse
指令的工作原理:


如果问题只出在资产上,您也可以将它们路由到
localhost:3838
应用程序:

# /var/www/example.com/routes/web.php
Route::get('/app/{any}', function($any) {
    return Response::make(
        file_get_contents("http://localhost:3838/$any")
    );
})->where('any', '.*');

Route::get('/{assets}', function($assets) {
    return Response::make(
        file_get_contents("http://localhost:3838/$assets")
    );
})->where('assets', '.*(png|jpe?g|js)');

我认为Jens Segers有一个软件包,可以让PHP模拟
ProxyPass
指令:

下面是GitHub自述文件中的一个示例:

use Proxy\Proxy;
use Proxy\Adapter\Guzzle\GuzzleAdapter;
use Proxy\Filter\RemoveEncodingFilter;
use Zend\Diactoros\ServerRequestFactory;

// Create a PSR7 request based on the current browser request.
$request = ServerRequestFactory::fromGlobals();

// Create a guzzle client
$guzzle = new GuzzleHttp\Client();

// Create the proxy instance
$proxy = new Proxy(new GuzzleAdapter($guzzle));

// Add a response filter that removes the encoding headers.
$proxy->filter(new RemoveEncodingFilter());

// Forward the request and get the response.
$response = $proxy->forward($request)->to('http://example.com');

// Output response to the browser.
(new Zend\Diactoros\Response\SapiEmitter)->emit($response);

你能澄清你所说的“Laravel不重写URL…”是什么意思吗?如果在
/app/{any}
路径内输出
dd(“http://localhost:3838/$any”)你看到了什么?在
/app/{any}
路线中,我添加了
dd(“http://localhost:3838/$any”)。当我访问
http://example.com/app/shared
我明白了
“http://localhost:3838/shared“
只是澄清一下,
localhost:3838
已经开发好了,您正试图在Laravel中制作一个代理?@Diogo是的,没错。@DiogoSgrillo这只是问题的一个症状。应用程序(
localhost:3838
)认为请求路径是
localhost:3838
,因此它返回该路径下的资产(例如:
localhost:3838/resource.jpg
),当它需要将它们作为
localhost:3838/app/resource.jpg
返回时,应用程序需要知道它正在
/app
下运行。对不起,但这不行。经过更多的研究,我意识到我正试图模仿Apache指令
ProxyPass
ProxyPassReverse
的行为。这些指令在HTTP头到达
localhost
app之前修改它。当
localhost
应用程序响应时,将再次修改标题,然后再将其发送回用户浏览器。因此,PHP还必须修改HTTP头以获得与Apache相同的行为。
file\u get\u contents
函数只是一个hack,但它不会修改标题。