我试图使用OAuth 2.0MAC授权Paysera,但我总是收到401错误.你能给我指出我做错了什么吗?

这是一个规格:https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-http-mac-02

以下是我的代码:

    private function _getTs() {
        return time();
    }

    private function _getNonce() {
        return uniqid();
    }

    private function _getMac($ts, $nonce, $method, $path, $host, $port, $key) {
        return base64_encode(hash_hmac("sha256", implode("\n", Array(
            $ts,
            $nonce,
            $method,
            $path,
            $host,
            $port,
            "",
        )), $key, true));
    }

    private function _getHeader($id, $method, $path, $host, $port, $key) {
        $ts = $this->_getTs();
        $nonce = $this->_getNonce();
        $mac = $this->_getMac($ts, $nonce, $method, $path, $host, $port, $key);

        $params = Array(
            "id" => $id,
            "ts" => $ts,
            "nonce" => $nonce,
            "mac" => $mac,
        );

        $parts = [];
        foreach ($params as $name => $value) {
            $parts[] = $name . '="' . $value . '"';
        }

        return "MAC " . implode(", ", $parts);
    }

    public function test() {
        $httpClient = new \Bitrix\Main\Web\HttpClient();
        $httpClient->setHeader("Authorization", $this->_getHeader(
            KEY_ID,
            "GET",
            "/rest/v1/post-offices",
            "delivery-api.paysera.com",
            443,
            KEY,
        ));
        $httpClient->query("GET", "https://delivery-api.paysera.com/rest/v1/post-offices");
        return $httpClient->getResult();
    }

推荐答案

以下是我对这个问题的最终解决方案.请注意,您必须启用递送服务并在Paysera网站上设置它们,这是我的主要问题:

private function _getTs() {
    return time();
}

private function _getNonce() {
    return uniqid();
}

private function _getExt($body) {
    if ($body) {
        return http_build_query(Array(
            "body_hash" => base64_encode(hash("sha256", $body, true)),
        ));
    }
    return null;
}

private function _getMac($ts, $nonce, $method, $pathQuery, $host, $port, $ext, $key) {
    return base64_encode(hash_hmac("sha256", implode("\n", Array(
        $ts,
        $nonce,
        $method,
        $pathQuery,
        $host,
        $port,
        $ext,
        null,
    )), $key, true));
}

private function _getHeader($id, $method, $pathQuery, $host, $port, $body, $key) {
    $ts = $this->_getTs();
    $nonce = $this->_getNonce();
    $ext = $this->_getExt($body);
    $mac = $this->_getMac($ts, $nonce, $method, $pathQuery, $host, $port, $ext, $key);

    $mac = Array(
        "id" => $id,
        "ts" => $ts,
        "nonce" => $nonce,
        "mac" => $mac,
    );

    if ($ext) {
        $mac["ext"] = $ext;
    }

    return "MAC " . implode(", ", array_map(function($key, $value) {
        return $key . "=\"" . $value . "\"";
    }, array_keys($mac), $mac));
}

private function _getResult($method, $path, $arQuery = null, $arBody = null) {
    $url = self::_URL . $path;

    if ($arQuery && is_array($arQuery)) {
        $url = $url . "?" . http_build_query($arQuery);
    }

    $body = null;
    if ($arBody && is_array($arBody)) {
        $body = \Bitrix\Main\Web\Json::encode($arBody);
    }

    $uri = new \Bitrix\Main\Web\Uri($url);
    $pathQuery = $uri->getPathQuery();
    $host = $uri->getHost();
    $port = $uri->getPort();

    $header = $this->_getHeader(
        $this->_id,
        $method,
        $pathQuery,
        $host,
        $port,
        $body,
        $this->_key,
    );

    $cache = \Bitrix\Main\Data\Cache::createInstance();
    if ($cache->initCache(86400, \Bitrix\Main\Web\Json::encode(Array(
        "method" => $method,
        "path" => $path,
        "query" => $arQuery,
        "body" => $arBody,
    )))) { 
        $vars = $cache->getVars();

        return $vars;
    } elseif ($cache->startDataCache()) {
        $httpClient = new \Bitrix\Main\Web\HttpClient();
        $httpClient->setHeader("Authorization", $header);
        $httpClient->query($method, $url, $body);
        
        $result = $httpClient->getResult();
        $result = \Bitrix\Main\Web\Json::decode($result);
        
        $cache->endDataCache($result);

        return $result;
    }
}

public function getMethods($projectId = null, $fromCountryCode = null, $toCountryCode = null, $shipments = null) {
    $arBody = Array();
    if (is_string($projectId)) {
        $arBody["project_id"] = $projectId;
    }
    if (is_string($fromCountryCode)) {
        $arBody["from_country_code"] = $fromCountryCode;
    }
    if (is_string($toCountryCode)) {
        $arBody["to_country_code"] = $toCountryCode;
    }
    if (is_array($shipments)) {
        foreach ($shipments as $shipment) {
            if (is_int($shipment["weight"]) &&
                is_int($shipment["width"]) &&
                is_int($shipment["length"]) && 
                is_int($shipment["height"])
            ) {
                $arBody["shipments"][] = $shipment;
            }
        }
    }

    return $this->_getResult("PUT", "methods", null, $arBody)["list"];
}

Php相关问答推荐

用户信息更新期间Laravel邮箱验证问题

如何在Livewire中验证多个 Select 字段

在函数内部获取一致的单选按钮值以更新WordPress用户数据

如何使用这种格式构建XML?

通过注册在Laravel中分配角色

将数组推送到数组时,数组推送()出现问题

Symfony5:如何在不登录的情况下使API路由可访问?

在WooCommerce管理中 for each 运输方法设置添加自定义字段

WooCommerce短代码,显示特定产品的购物车徽章中的当前数量

使用php ZipArhive类将Zip压缩文件分成多个部分

调用模型[App\Models\Employee]上未定义的关系[title]

对 WooCommerce 购物车和 checkout 中显示的运输方式进行排序

Filament PHP v3:在禁用的表单字段上,ID 不会写入数据库

ACF 更新字段功能不更新 WordPress 中的任何数据

在wordpress注销后防止后退操作

为 WordPress 页面创建新功能

来自 GoDaddy 的邮箱在 Gmail 中显示为via

显示时间范围内的可用空位,同时考虑已预订的空位

Laravel 测试 assertJsonMissing 不适用于唯一的键.为什么?

PHP 中的正则表达式,具有字符范围,但不包括特定字符