使用前端控制器脚本时无法从基本身份验证中排除路径

使用前端控制器脚本时无法从基本身份验证中排除路径

我有一个小型的 PHP/Apache2 Web 应用程序,我想在其中执行两个看似不兼容的操作:

  1. 通过单个 PHP 脚本(如果你愿意的话,可以称为“前端控制器”)路由所有请求
  2. 使用 HTTP 基本身份验证保护除 API 调用之外的所有内容

我可以单独满足任何一个要求,但当我试图同时满足这两个要求时,我就会受阻。我试图仅使用 Apache 配置来实现这些要求,但没有任何理由。

以下是作为示例提出的要求。GET此 URL 的请求:

http://basic/api/listcars?max=10

front.php应该无需基本身份验证即可发送。front.php将获取/api/listcars?max=10并执行其需要执行的任何操作。

以下是我认为应该可行的方法。在我的文章中,/etc/hosts我添加了

127.0.0.1 basic

我正在使用这个 Apache 配置:

<Location />
  AuthType Basic
  AuthName "Home Secure"
  AuthUserFile /etc/apache2/passwords
  require valid-user
</Location>

<VirtualHost *:80>
  ServerName basic
  DocumentRoot /var/www/basic
  <Directory /var/www/basic>
    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteCond %{SCRIPT_FILENAME} !-f
      RewriteCond %{SCRIPT_FILENAME} !-d
      RewriteRule ^(.*)$ /front.php/$1 [QSA,L]
    </IfModule>
  </Directory>
  <Location /api>
    Order deny,allow
    Allow from all
    Satisfy any
  </Location>
</VirtualHost>

# another extant vhost in the same Apache2 config/server, for completeness
<VirtualHost *:80>
  ServerName dustbin
  ServerAlias *.dustbin
  DocumentRoot /var/www/dustbin
</VirtualHost>

但我仍然总能得到HTTP 401: Authorization Required回应。我可以通过将其<Location /api>改为

<Location ~ /api>

但这允许我完成比我想要的更多的基本身份验证。

我也尝试将该<Directory /var/www/basic>部分更改为<Location />,但这也不起作用(并且导致PATH_TRANSLATED传递给脚本的一些奇怪的值)。

我搜索了一下,发现了很多选择性排除基本身份验证的例子,但没有一个包含前端控制器。

我当然可以做一些事情,比如在前端控制器中处理基本身份验证,但如果我可以让 Apache 来做这件事,我就能将所有身份验证逻辑排除在我的 PHP 代码之外。

一位朋友建议将其拆分为两个虚拟主机,我知道这也是可行的。实际上,这曾经是两个独立的虚拟主机。

<Location />在虚拟主机之外,因为我希望所有虚拟主机默认都需要基本身份验证。我希望做出的一个例外是针对此特定虚拟主机上以 /api 开头的所有 URI。我省略了其他虚拟主机,因为它们似乎与我的问题无关。

我在 Ubuntu 12.04 上使用 Apache 2.2.22 / PHP 5.3.10。

答案1

由于RewriteRule修改路径的是在<Directory>块中(这样做是为了获得%{SCRIPT_FILENAME}完整的文件路径),因此该[PT]标志隐含在规则中。由于该[PT]标志适用,新请求的 URL 将根据位置重新映射 - 并且该<Location /api>部分不再适用于该请求。

因此,考虑到这一点,还有几个选择。

  • 将重写规则从<Directory>块中取出。

    <VirtualHost *:80>
      ServerName basic
      DocumentRoot /var/www/basic
      RewriteEngine On
      RewriteCond /var/www/basic%{REQUEST_URI} !-f
      RewriteCond /var/www/basic%{REQUEST_URI} !-d
      RewriteRule ^(.*)$ /front.php/$1 [QSA,L]
      <Location /api>
        Order deny,allow
        Allow from all
        Satisfy any
      </Location>
    </VirtualHost>
    
  • 使用该正则表达式<Location>- 它可以被限制以防止意外匹配。

    <Location ~ "(^|^/front\.php)/api/[^/]*$">
    
  • 使用FallbackResource而不是mod_rewrite

    FallbackResource /front.php
    

相关内容