Symfony 2中请求头缺少Authorization头信息?

49
我正在尝试在Symfony 2中实现自定义身份验证提供程序。我使用Fiddler发送了一个测试请求并在服务器端打印了所有标头;但是,Authorization标头确实缺失。
我做错了什么吗?
GET /RESTfulBackend/web/index.php HTTP/1.1
Authorization: FID 44CF9590006BF252F707:jZNOcbfWmD/
Host: localhost
User-Agent: Fiddler
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: it-it,it;q=0.8,en-us;q=0.5,en;q=0.3

监听器仅打印标头并退出:

class HMACListener implements ListenerInterface
{
    private $securityContext;

    private $authenticationManager;

    public function handle(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        print_r($request->headers->all()); 
        die();
     }
}

响应缺少Authorization头:

Array
(
    [host] => Array
        (
            [0] => localhost
        )
    [user-agent] => Array
        (
            [0] => Fiddler
        )
    [accept] => Array
        (
            [0] => text/html,application/xhtml+xml,application/xml
        )
    [accept-language] => Array
        (
            [0] => it-it,it;q=0.8,en-us;q=0.5,en;q=0.3
        )
)

请查看这个类似问题的答案 [https://dev59.com/h2Yr5IYBdhLWcg3wytLe]。 - Wilt
9个回答

65

您必须将此代码添加到 virtualhost 标签中。

如果将其放在 Directory 标签中,则无法正常工作。

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

1
这对我来说非常有效,你能解释一下它是做什么的吗? - chacham15
1
谢谢,它可以工作,但可能存在问题。看起来即使在传入请求中没有授权标头字段,也会创建一个。这不应该是行为。 - webaba
这是正确的,即使请求中没有授权头字段,它也会创建一个。对此有什么想法吗? - mezod
2
我在 .htaccess 文件中添加了以下内容:RewriteCond %{HTTP:Authorization} .+ - mezod
将其添加到.htaccess后,它可以正常工作。 - Vahid Amiri
显示剩余5条评论

34
Akambi的回答对我没有用,但我在php网站上找到了这个答案:
“CGI/FastCGI Apache下缺少授权标头的解决方法:
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0

现在,如果客户端发送授权头,则PHP应自动声明$_SERVER [PHP_AUTH_ *]变量。

感谢derkontrollfreak + 9hy5l!

谢谢。你知道为什么头部没有发送吗? - anna
已经尝试了这个修复方法,但我的脚本仍无法响应 401 头。 - Twisty
这是唯一可行的解决方案,“RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]” 的方法不起作用。 - tom10271
通过将其添加到VirtualHost配置文件中,这对我起作用了。在.htaccess中也应该可以正常工作,只需确保在请求到达您的应用程序之前没有代理、容器等。 - Omar Tariq

20

这个经过验证的解决方案曾经对我有用,可以获取 Authorization header。不过,当传入请求中没有 Authorization header 时,它会生成一个空的 Authorization header。这是我解决它的方法:

RewriteEngine On
RewriteCond %{HTTP:Authorization} .+
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

11

当编写具有自定义Authorization头的公共API时,我遇到了相同的问题。为了修复HeaderBag,我使用了一个监听器:

namespace My\Project\Frontend\EventListener;

use Symfony\Component\HttpFoundation\HeaderBag;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;

/**
 * Listener for the REQUEST event. Patches the HeaderBag because the
 * "Authorization" header is not included in $_SERVER
 */
class AuthenticationHeaderListener
{
    /**
     * Handles REQUEST event
     *
     * @param GetResponseEvent $event the event
     */
    public function onKernelRequest(GetResponseEvent $event)
    {
        $this->fixAuthHeader($event->getRequest()->headers);
    }
    /**
     * PHP does not include HTTP_AUTHORIZATION in the $_SERVER array, so this header is missing.
     * We retrieve it from apache_request_headers()
     *
     * @param HeaderBag $headers
     */
    protected function fixAuthHeader(HeaderBag $headers)
    {
        if (!$headers->has('Authorization') && function_exists('apache_request_headers')) {
            $all = apache_request_headers();
            if (isset($all['Authorization'])) {
                $headers->set('Authorization', $all['Authorization']);
            }
        }
    }
}

并将其绑定到服务定义中的kernel.request

services:
  fix_authentication_header_listener:
    class: My\Project\Frontend\EventListener\AuthenticationHeaderListener
    tags:
      - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 255 }

请注意,您需要安装PHP的Apache扩展程序,以便使用apache_request_headers函数。 - Loïc Faugeron
1
使用Symfony 5.4,GetResponseEvent已更名为RequestEvent。 - Oleh Diachenko

7

在其他选项无效时,适用于Apache 2.4的另一种选项是在相关的<Directory>上下文中设置CGIPassAuth选项,如下所示:

CGIPassAuth On

根据文档,它自Apache 2.4.13版本开始可用。


1
这是对我有效的解决方案。否则,Authorization头在getallheaders和$ _SERVER中都会丢失。 - G_Gus

7

授权头用于http基本身份验证,如果格式无效,则Apache将放弃该头。请尝试使用其他名称。


谢谢。例如,亚马逊S3如何使用它?http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html - user1098965
如果您查看Apache实现,它期望请求令牌为base_64编码字符串,并在服务器端对其进行base64解码并设置PHP_AUTH_USERPHP_AUTH_PW服务器变量。正如您所看到的,该实现是特定于服务器的。因此,Amazon S3 Web服务器以不同的方式实现了该方案。 - Mun Mun Das
那你会建议使用 apache_request_headers() (仅适用于 Apache),还是使用自定义标头? - user1098965
你可以创建一个 Apache 模块,使得你的认证方案与 HTTP 基本认证兼容。例如,可以查看模块。或者,你可以使用自定义标头,例如 X-FID-Authorization - Mun Mun Das
2
据我所知,Apache将接受任何格式的授权标头。而PHP会丢弃除有效的基本或摘要标头之外的任何内容。 - Mika Tuupola
似乎我们可以使用头部名称“Php-Auth-Digest”作为“Authorization”的替代方案。请参阅Symfony\Component\HttpFoundation\ServerBag::getHeaders()。 - Artur Cichosz

0
如果您正在使用Apache,并且已经在您的.htaccess文件中设置了头部覆盖,但仍然遇到401错误。
RewriteCond %{HTTP:Authorization} .+
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]

然后确保在您的VirtualHost中启用配置覆盖。将Directory标签中的AllowOverride参数的值设置为All

<VirtualHost *:80>
    ...
    <Directory /var/www/***>
        AllowOverride All
        ...
    </Directory> 

</VirtualHost> 

在进行更改后,不要忘记重新启动Apache


0

另一种解决方案是将您的 PHP 处理程序更改为以 Apache 模块 的形式运行 PHP,而不是作为 CGI 应用程序


虽然这不是一个好的解决方案,因为作为模块比作为CGI更慢。此外,在开发过程中,缓存和日志文件夹的权限存在问题。 - Jorj
@Jorj,“问题”您能详细说明一下吗?我敢打赌这只是一个配置问题。这是一个可行的解决方案。从未说过它是“最好的”。那只是个人的看法。 - Wilt
当你作为Unix系统上的开发人员创建文件时,你会在自己的用户下创建文件,对吧?然后你会从控制台启动一些命令,这些命令会在缓存和日志文件夹中创建文件。如果PHP被配置为Apache模块,它将与Apache的用户一起运行,即“www”或“nobody”或类似的用户。结果它将尝试覆盖你在缓存和日志文件夹中创建的文件,并且会因为这些文件属于另一个所有者而抛出错误。当然,也有解决方法,但仍然是额外的麻烦。 - Jorj

0

我们应该在服务器端授权此标题“Authorization”,

使用nelmioCorsBundle也很简单 nelmio_cors: defaults: allow_credentials:false allow_origin:[] allow_headers:[] allow_methods:[] expose_headers:[] max_age:0 hosts:[] origin_regex:false forced_allow_origin_value:~ paths: '^/api/': allow_origin:['*'] allow_headers:['Authorization']


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