我一直关注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×tamp=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)
的值不相同。
答案 0 :(得分:0)
因此,您正在构建包含共享密钥的哈希。这样可以保证$ code,$ shop和$ timestamp的值没有被篡改,并且请求来自拥有共享密钥的人。
所以我可以想到以下可能导致这种情况发生的情况:
答案 1 :(得分:0)
我知道您是否已部署到Shopify可以公开访问的服务器上?
在我看来,你在本地做并尝试在本地验证oauth,我会正确验证,但是对于重定向,如果肯定会失败。
答案 2 :(得分:0)
Shopify要求应用服务器受SSL保护。由于这个原因,Oauth将失败。我暂时把头撞在这个上。一些较旧的文档和教程说你可以使用localhost进行测试,但这不再是真的。
答案 3 :(得分:0)
返回“请求不是来自Shopify”错误的函数是错误地计算hmac代码。我在其他几个图书馆看过这个,特别是那些由Shopify以外的人维护的图书馆。
hmac签名的部分必须:
hmac
和signature
字段获取。 (这就是这个,大多数第三方库都错了。他们经常构建文档显示为余数的字段,但这是不正确的,因为文档没有显示可能存在的所有字段,并且如果没有更新文档,API可以更改。)ksort()
功能完成)。%
变为%25
)。http_build_query($toTest)
)hash_hmac('sha256', $toTest, $secret);
)以下是您的工作示例:
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
}