我有一个小型的 PHP/Apache2 Web 应用程序,我想在其中执行两个看似不兼容的操作:
- 通过单个 PHP 脚本(如果你愿意的话,可以称为“前端控制器”)路由所有请求
- 使用 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