PHP POST请求中缺少授权头信息

101

我现在正在尝试在调用POST请求的PHP脚本中读取授权头。 授权标头填充了一个令牌。 看起来授权标头在到达我的PHP脚本之前被某种方式删除了。 我使用Postman(Chrome插件)执行post请求,并在我的PHP脚本中启用了CORS。 我无法直接访问apache服务器。

HTTP请求:

Accept:*/*
Accept-Encoding:gzip,deflate
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,ja;q=0.2
Authorization:Bearer mytoken
Cache-Control:no-cache
Connection:keep-alive
Content-Length:32
Content-Type:text/plain;charset=UTF-8
Host:www.myhost.com
Origin:chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
 User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)       
 Chrome/38.0.2125.104 Safari/537.36

PHP脚本:

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type,      Accept");
header("Content-Type: application/json");

$headers = getallheaders();
echo $headers['Authorization'];

上述脚本输出''(表示没有内容)。


有人有什么其他的想法可以检查来调试这个问题吗? - jimmy
检查 PHP 变量 $_SERVER 数组,以防您的网站被重定向 -> REDIRECT_AUTHORIZATION。 - 9swampy
13个回答

270

不知何故,Authorization header被去掉了。通过在我的.htaccess文件中添加以下几行代码,我得以让它正常工作。

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

2
当我在Php 5.4和Apache上尝试使用HTTP基本授权来访问我的REST API时,遇到了同样的问题。我修改了.htaccess文件以支持rest api的RewriteEngine On,查询它们时所有请求头都似乎已经存在,除了PHP中的授权。您的修复方法是正确的,谢谢! - Deemoe
17
4年后在PHP 7.2上,这仍然很相关!修复得真棒! - spice
18
我本来想点赞这个...但是后来我意识到我已经在上次遇到这个问题时点过赞了。 - Jerry
5
优秀的解决方案...现在能有人解释一下发生了什么吗?这只会在一些服务器上发生。为什么它会被剥离? - James John McGuire 'Jahmic'
11
我也对此很好奇;显然出于安全原因,Apache默认不传递“Authorization”标头。相反,您必须手动启用它(大约在2.4.13版本),使用“CGIPassAuth”指令,在“.htaccess”或目录配置中有效。此功能也适用于之前的版本,但我找不到解释旧版本的文档。 - patricknelson
显示剩余8条评论

80

我首先需要将以下内容添加到我的 Apache 配置文件中:

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

在Linux中,在/etc/apache2/apache2.conf文件中。

在使用Homebrew的Mac中,在/usr/local/etc/httpd/httpd.conf文件中。

在使用“native”Apache的Mac中:/private/etc/apache2/httpd.conf 或者:/etc/apache2/httpd.conf

无论什么原因,在.htaccess中添加这个并没有起作用:

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

更新 2022:

根据多个评论,您可以通过多种方式实现相同的结果(但由于几年前我在所有项目中转换到了nginx,无法确认):

您可以在每个项目的 .htaccess 中放置 SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1,也可以在 httpd.conf 上“全局”使用,或者在 <VirtualHost> 块内的 httpd-vhosts.conf 文件上每个项目使用。


12
你可以在 .htaccess 文件中添加 SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1。这对我有用。 - Mohit
2
它对我有用。我正在使用aws lightsail,所以我将代码添加到/opt/bitnami/apache2/conf/httpd.conf中。另外,我认为重启服务器是必要的。sudo /opt/bitnami/ctlscript.sh restart apache。 - mazend
@Mohit 对于我来说,这必须在Apache配置文件(或虚拟主机配置)中进行 - 也就是说,当添加到.htaccess文件中时它不起作用。我不知道为什么会这样,因为我已经设置了“AllowOverride ALL”。 - Ade
这也解决了Bitnami WordPress服务器上的问题。Apache2配置文件位于opt/bitnami/apache2/conf/httpd.conf中,我添加了SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1,并成功消除了错误。谢谢。 - Hevski
1
仅供澄清:您可以在每个项目的 .htaccess 文件中放置 SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1,也可以在 httpd.conf 中“全局”设置,或者在 <VirtualHost> 块内的 httpd-vhosts.conf 文件中为每个项目设置。 - ViBoNaCci
显示剩余4条评论

25

最优雅的解决方案是启用.htaccess中的此指令。

CGIPassAuth On

这个指令是 Apache 核心的一部分,不需要启用任何特殊的模块。在这里可以查看文档。

当使用 php-fpm 与 Apache 配合(而不是直接在 Apache 中使用 php 模块)时,就会出现问题。

这是一项安全措施,防止敏感数据通过 FastCGI 从 Apache 传递到 PHP。

这个解决方案不仅修复了$_SERVER["HTTP_AUTHORIZATION"],还包括了$_SERVER["PHP_AUTH_USER"],它被用于在 PHP 的官方文档中描述的“基础认证”中。

在我看来,所有其他涉及通过 SetEnvIf 或使用 RewriteRule 设置 HTTP_AUTHORIZATION 环境变量的解决方案都是变通方法,并没有解决根本问题。

我在 2021 年使用 PHP 7.4 测试过这个解决方案。


这在使用FastCGI处理程序的PHP 8.0.10中有效! - waseemrakab
非常好!我之前一直收到“400 Bad Request: JSON Web Token not set in request”的错误提示,但现在已经解决了。 - zoran
使用PHP 8.2进行工作 已启用PHP-FPM,但无法接收授权头,这解决了问题。 - undefined

17

如果您使用WHM + CPanel + PHP,并且如果您的显示结果像这样,缺少授权

Translated:

如果你使用 WHM + CPanel + PHP,而且你的显示结果像这里缺少Authorization一样。

Array
(
    [Host] => domain.com
    [Connection] => keep-alive
    [Cache-Control] => max-age=0
    [Upgrade-Insecure-Requests] => 1
    [User-Agent] => Mozilla/5.0
    [Accept] => text/html,application/xhtml+xml
    [Sec-Fetch-Site] => none
    [Sec-Fetch-Mode] => navigate
    [Sec-Fetch-User] => ?1
    [Sec-Fetch-Dest] => document
    [Accept-Encoding] => gzip, deflate, br
    [Accept-Language] => en
)

现在只需要按照以下步骤进行操作。

第1步:添加.htaccess文件

RewriteEngine On

RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

步骤2:在您的PHP文件中添加,如index.php

1. getallheaders();

2. apache_request_headers();
 
3. $SERVER['REDIRECT_HTTP_AUTHENTICATION'];

您可以使用任何一个人。

第三步:前往 WHM 面板并按照以下步骤进行导航。

Home » Service Configuration » Apache Configuration » Include Editor » Pre VirtualHost Include » All Version 

添加这行内容

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

重启Apache服务器 (如果不重启服务器则无法正常工作)

步骤4:我的结果显示

Array
(
    [Authorization] => hhRbRZtypswriasabjn3xHT+9Fe9sWHjejhID/YTmookDdrN7WyTUULWwCvmMRiW0RaDRtozLVnvjnl
    [User-Agent] => PostmanRuntime/7.26.8
    [Accept] => */*
    [Cache-Control] => no-cache
    [Host] => domain.com
    [Accept-Encoding] => gzip, deflate, br
    [Connection] => keep-alive
    [Content-Type] => application/x-www-form-urlencoded
    [Content-Length] => 3
    [X-Https] => 1
)

这项工作已经完成。如果你按照这些步骤仍然遇到相同的错误,请在此处留言。


任何时候 @Sachem - Purvesh Tejani
如何在IIS web.config中实现此操作。 - Quentin Merlin
这是唯一对我有效的方法,我已经收藏了。谢谢分享。 - undefined

8
下面的数组保存了请求头,可能在$_SERVER变量中缺失。
$headers = apache_request_headers();

尤其是对于与'HTTP_X_REQUESTED_WITH' ajax头相关的内容,可以通过以下方式找到:

$headers['X_REQUESTED_WITH']

虽然这是正确的,我可以看到正确的标题在那里(这比使用.htaccess解决方案要好得多!),但数组中的键是区分大小写的。因此,在调整数组之前,您无法轻松访问它们... - Alexis Wilke
1
请参考以下答案,了解如何将数组的键转换为小写或大写:https://dev59.com/PG855IYBdhLWcg3wnFxO - Alexis Wilke
请注意!apache_request_headers()是一个只在使用Apache作为Web服务器时定义的函数。因此,所有使用nginx等其他服务器的人将被排除在外。 - Alex Abreu Mulet

3
我希望能针对一个具体的案例进行扩展之前的回答。
我正在使用在AWS (Lightsail)上的LAMP(bitnami),我的代码是使用CodeIgniter 3编写的。因此,我已经有了一个“.htacess”文件,并且其中包含以下内容:
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>

我想要实现jimmy的解决方案

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

但是怎么做呢?每个人似乎都在“建议”一些东西,但没有具体说明。使用多个重写条件/规则看起来很困难。我不是Apache专家,所以我必须进行实验。我成功地按照以下方式使其工作:

<IfModule mod_rewrite.c>
    RewriteEngine On
    
    RewriteCond %{HTTP:Authorization} ^(.*)
    RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
    
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>

现在,$_SERVER 数组中有一个 "HTTP_AUTHORIZATION" 键。

编辑: 另外似乎还有另一个键 "REDIRECT_HTTP_AUTHORIZATION" 值相同。


2
在我的情况下,我发现它在$_SERVER["REDIRECT_HTTP_AUTHORIZATION"]中。

1

对我来说,在PHP 8.1上启用PHP-FPM解决了这个问题,无需修改htaccess。


可能只是从CGI切换到PHP-FPM才是重点,PHP版本应该是不相关的。 - MAChitgarha

1

在我进行以下操作后,上述解决方案对我有效:修改httpd.conf文件:

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

为了使其生效,httpd.conf 必须在我的别名部分包含以下指令:
AllowOverride All
Options FollowSymLinks

第一个方法太过开放(是的,我知道),但如果您将AllowOverride None设置为否,则完全可以避免使用.htaccess。
此外,如果您不使用FollowSymLinks或类似选项(基于Apache文档),也可以避免使用RewriteRule。

如何在IIS中完成? - Quentin Merlin

1
我在某个地方(不记得是哪里了)找到了一个稍微不同的语法,我在项目的.htaccess文件中使用它也能正常工作。
RewriteEngine On
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接