用PHP

时间:2018-01-29 16:36:16

标签: php laravel authentication proxy

问题摘要

Flow diagram with authenticated users viewing content from a localhost app.

假设您运行服务器并希望仅为已使用用户名和密码登录的用户(经过身份验证的用户)提供localhost应用程序中的内容。

该应用在您的服务器上运行,但不向公众公开。它只能通过您服务器上的http://localhost:3838获得。

为简单起见,假设您运行localhost应用程序的方式如下:

cd my-private-folder
python3 -m http.server 3838

经过身份验证的用户应该可以转到http://example.com/app查看 localhost应用程序提供的内容。

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

问题

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

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

  • 使用Laravel PHP框架有一种简单的方法吗?

作为参考,有一个名为oxy的包在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标头未被修改。

例如:

要了解失败的原因,请参阅下面正确运行的Apache解决方案。 Apache有一个名为ProxyPassReverse的指令来修改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>

这个相关的答案帮助我更好地理解ProxyPassReverse指令的工作原理:

2 个答案:

答案 0 :(得分:0)

如果问题仅出在资产上,您可以将它们路由到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)');

答案 1 :(得分:0)

我认为Jens Segers有一个软件包可以让PHP模仿ProxyPass指令:https://github.com/jenssegers/php-proxy

以下是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);