Shopify应用程序生成shopify api令牌"此请求不是来自Shopify!"

时间:2016-03-26 11:17:45

标签: shopify

我一直关注shopify documentation生成shopify api令牌。

以下是 install.php

的代码
<?php

// Set variables for our request
$shop = "ecommerce-52";
$api_key = "6bdad749dxxxx24c462c7d2af";
$scopes = "read_orders,write_products";
$redirect_uri = "http://localhost/shopify/shopify-generating-api-token-guide/generate_token.php";
//$redirect_uri = "https://ecommerce-52.myshopify.com";

// Build install/approval URL to redirect to
$install_url = "https://" . $shop . ".myshopify.com/admin/oauth/authorize?client_id=" . $api_key . "&scope=" . $scopes . "&redirect_uri=" . urlencode($redirect_uri);

//print_r($install_url);
// Redirect
header("Location: " . $install_url);
die();

它重定向到安装应用页面,点击安装后我被重定向到

http://localhost/shopify/shopify-generating-api-token-guide/generate_token.php?code=86f5027cxxxxxxxxx9c5d&hmac=fcf1e1bexxxxxxxxa97b0f79ec1ec7b473e0bc36bf71&shop=ecommerce-52.myshopify.com&signature=12a6ab63c04d9844ff6xxxxxx0&timestamp=1458991225

但它说:

This request is NOT from Shopify!

这是我的generate_token.php

代码
<?php

// Get our helper functions
require_once("inc/functions.php");

// Set variables for our request
$shop = "ecommerce-52";
$api_key = "6bdad749xxxxxxx24c462c7d2af";
$shared_secret = "c679xxxxx3ac11474599";
$code = $_GET["code"];
$timestamp = $_GET["timestamp"];
$signature = $_GET["signature"];

// Compile signature data
$signature_data = $shared_secret . "code=" . $code . "shop=". $shop . ".myshopify.comtimestamp=" . $timestamp;

// Use signature data to check that the response is from Shopify or not
if (md5($signature_data) === $signature) {

    // Set variables for our request
    $query = array(
        "Content-type" => "application/json", // Tell Shopify that we're expecting a response in JSON format
        "client_id" => $api_key, // Your API key
        "client_secret" => $shared_secret, // Your app credentials (secret key)
        "code" => $code // Grab the access key from the URL
    );

    // Call our Shopify function
    $shopify_response = shopify_call(NULL, $shop, "/admin/oauth/access_token", $query, 'POST');

    // Convert response into a nice and simple array
    $shopify_response = json_decode($shopify_response['response'], TRUE);

    // Store the response
    $token = $shopify_response['access_token'];

    // Show token (DO NOT DO THIS IN YOUR PRODUCTION ENVIRONMENT)
    echo $token;

} else {
    // Someone is trying to be shady!
    die('This request is NOT from Shopify!');
}

我无法弄清楚我做错了什么。任何帮助,将不胜感激。

更新

我甚至尝试在Heroku上部署它(默认情况下是https),但仍然没有运气。我无法理解为什么$signature$md5($signature_data)的值不相同。

4 个答案:

答案 0 :(得分:0)

因此,您正在构建包含共享密钥的哈希。这样可以保证$ code,$ shop和$ timestamp的值没有被篡改,并且请求来自拥有共享密钥的人。

所以我可以想到以下可能导致这种情况发生的情况:

  1. $ shared_secret,$ code,$ shop,$ timestamp已被篡改 (不太可能)
  2. 计算哈希的方法是错误的 - $ signature_data = $ shared_secret。 “code =”。 $ code。 “店=”。 $店 。 “.myshopify.comtimestamp =”。 $时间戳; (不太可能,如果它的例子 代码)
  3. 客户端上的md5已损坏(不太可能)
  4. BTW我很惊讶你不需要在某处使用base64编码。 (不太可能 你还没有改变示例代码)
  5. 你的$ shared_secret是 不同(这是我先检查的)

答案 1 :(得分:0)

我知道您是否已部署到Shopify可以公开访问的服务器上?

在我看来,你在本地做并尝试在本地验证oauth,我会正确验证,但是对于重定向,如果肯定会失败。

答案 2 :(得分:0)

Shopify要求应用服务器受SSL保护。由于这个原因,Oauth将失败。我暂时把头撞在这个上。一些较旧的文档和教程说你可以使用localhost进行测试,但这不再是真的。

答案 3 :(得分:0)

哇,我很惊讶Shopify是(仍然?)链接到那个。那个示例代码是各种错误的。

返回“请求不是来自Shopify”错误的函数是错误地计算hmac代码。我在其他几个图书馆看过这个,特别是那些由Shopify以外的人维护的图书馆。

hmac签名的部分必须

  1. 通过从响应数据中删除 hmacsignature字段获取。 (这就是这个,大多数第三方库都错了。他们经常构建文档显示为余数的字段,但这是不正确的,因为文档没有显示可能存在的所有字段,并且如果没有更新文档,API可以更改。)
  2. 按键名称按字母顺序排序(在PHP中,可以使用ksort()功能完成)。
  3. 使用查询字符串编码值替换特殊字符(即 - %变为%25)。
  4. 变成查询字符串。 (在PHP中:http_build_query($toTest)
  5. 使用sha256和共享密钥对每个hmac标准进行哈希 。 (hash_hmac('sha256', $toTest, $secret);
  6. 以下是您的工作示例:

    public function verifyRequest($request, $secret) {
        // Per the Shopify docs:
        // Everything except hmac and signature...
    
        // Plain PHP, pass in $request as assoc array of all query string items
        $hmac = $request['hmac'];
        unset($request['hmac']);
        unset($request['signature']);
        $signature = $request;
    
        // Laravel or other framework with a first-class Request object
        // Use this or the unsets, above, not both
        $signature = $request->except(['hmac', 'signature']);
    
    
    
        // Sorted lexilogically...
        ksort($signature);
    
        // Special characters replaced...
        foreach ($signature as $k => $val) {
            $k = str_replace('%', '%25', $k);
            $k = str_replace('&', '%26', $k);
            $k = str_replace('=', '%3D', $k);
            $val = str_replace('%', '%25', $val);
            $val = str_replace('&', '%26', $val);
            $signature[$k] = $val;
        }
    
        // Hashed per hmac standards, using sha256 and the shared secret
        $test = hash_hmac('sha256', http_build_query($signature), $secret);
    
        // Verified when equal
        return $request->input('hmac') === $test; // Laravel/frameworked code
        return $hmac === $test; // Vanilla PHP/using the array unset block
    }