使用eBay令牌认证已经挣扎了几天。 我发现很难理解如何获取新令牌,在注册开发者计划帐户之后,我请求了密钥集并获得了它们,之后我授权访问Auth' Auth令牌,该令牌承诺持续18个月,是的,令牌仅适用于交易,购物和寻找API。
但是,当您需要执行购买,销售和商务时,您必须获得oauth令牌。你可以做所谓的"单用户应用程序"样式并在用户令牌工具上登录oauth,并获得2小时到期的oauth。
稍后,令牌过期,你就失去了对上述api的访问权限。我尝试从Trading>获取令牌获取会话ID,交易>获取令牌,但在向Fetch令牌提供会话ID后,它说:"最终用户尚未完成Auth& Auth签到流程。"虽然有一个有效的18个月令牌,但它会一直返回此错误。
是否有任何关于此的示例文章,任何人都可能阅读或写过?
答案 0 :(得分:27)
你的困惑并非毫无根据。我自己对这个API流程的体验以及official dev forums的很大一部分的体验一直很紧张。以下详细介绍了生成无关的过程,了解您是要连接到单个,专用帐户还是多个用户帐户。
有official guide,它解释了整个过程,所以我在这里重新创建整个指南犹豫不决。我可以提供一个摘要(我建议您在尝试通过应用程序之前使用Postman进行以下操作):
https://api.ebay.com/oauth/api_scope/sell.inventory
范围。找出您需要的端点,然后转到每个端点的API文档,找到范围部分。现在,get请求如下所示:
`https://signin.sandbox.ebay.com/authorize?
client_id=<your-client-id-value>&
redirect_uri=<your-RuName-value>&
response_type=code&
scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.account%20
https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.inventory`
还建议您添加state
查询字符串,为了便于使用,我省略了该字符串,但您应该研究what they are以及为什么建议将其用于OAuth。
code
查询字符串。如果您正在为多个用户开发应用程序并计划让他们在此页面上登录,那么您需要配置您的应用程序以获取确认响应,该响应将是上述URL,并从中提取代码。此代码非常短暂。如果您通过浏览器手动检索它,则需要快速完成后续步骤。您现在需要对https://api.sandbox.ebay.com/identity/v1/oauth2/token执行POST请求。请参阅以下结构:
HTTP method: POST
URL (Sandbox): https://api.sandbox.ebay.com/identity/v1/oauth2/token
HTTP headers:
Content-Type = application/x-www-form-urlencoded
Authorization = Basic <B64-encoded-oauth-credentials> (A base64-encoded value made from your client ID and client secret, separated by colon. For example, in PHP you could generate it with: `base64_encode ("fakeclientid123:fakeclientsecret123")`)
Request body (wrapped for readability):
grant_type=authorization_code& (literally the string "authorization_code")
code=<authorization-code-value>& (code retreived in previous step)
redirect_uri=<RuName-value> (same RuName as earlier)
如果成功,此请求将返回如下内容:
{
"access_token": "v^1.1#i^1#p^3#r^1...XzMjRV4xMjg0",
"token_type": "User token",
"expires_in": 7200,
"refresh_token": "v^1.1#i^1#p^3#r^1...zYjRV4xMjg0",
"refresh_token_expires_in": 47304000
}
我们追求的是oauth令牌,持续时间 2小时。第二个令牌是刷新令牌,持续约18个月。保持此令牌安全,不要共享它,也不要在您的应用程序中对其进行硬编码。从此时起,您的应用应使用此令牌执行刷新调用,以便在需要时获取新的oauth。一旦18个月启动,或者用户再次执行“允许访问”过程,您将需要执行上述所有操作以生成新的刷新令牌。假设API没有改变那一点。
值得注意的是,18个月的生命周期不是OAuth刷新的正常程序,通常每次使用旧刷新令牌时都会返回一个新的刷新令牌。
刷新oauth:
HTTP method: POST
URL (Sandbox): https://api.sandbox.ebay.com/identity/v1/oauth2/token
HTTP headers:
Content-Type = application/x-www-form-urlencoded
Authorization = Basic <B64-encoded-oauth-credentials>
Request body (wrapped for readability):
grant_type=refresh_token&
refresh_token=<your-refresh-token-value>&
scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.account%20
https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope%2Fsell.inventory
我希望这有帮助!
答案 1 :(得分:4)
对于那些与之斗争的人 - 请确保使用编码的代码/令牌。
我几乎失去了理智,试图找出错误的原因,因为ebay返回刷新令牌已解码
答案 2 :(得分:1)
对于任何挣扎的人,请注意第4步中的URL与eBay上给出的URL不同。 eBay上的URL以https://auth.sandbox.ebay.com/oauth2/authorize
开头,但步骤4中的URL以https://signin.sandbox.ebay.com/authorize
开头
答案 3 :(得分:0)
我发现@FullStackFool的上述帖子非常有帮助。基于此,我构建了一个类,该类从本地数据库获取当前令牌,如有需要,刷新令牌,显示获取新刷新令牌的说明,或处理代码以生成新的刷新令牌。
类是用PHP 5.6(道歉-旧的内部订单管理系统)编写的,但可以轻松升级到PHP 7 / Laravel等。
构造函数仅采用一个可选值-这是ebay在验证/登录以获取新令牌时由ebay生成的URL字符串。如果将其提供给构造函数,它将对其进行解析,获取“代码”部分,然后获取新的令牌并刷新令牌。
希望代码能自我解释-我已尝试对其进行注释。希望其他人觉得这有用。
数据库表(EbayTokens):
CREATE TABLE IF NOT EXISTS `EbayTokens` (
`TokenID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`TokenValue` text,
`TokenCreated` datetime DEFAULT NULL,
`TokenLifetime` int(11) unsigned DEFAULT NULL,
`RefreshTokenValue` text,
`RefreshTokenCreated` datetime DEFAULT NULL,
`RefreshTokenLifetime` int(11) unsigned DEFAULT NULL,
`TokenType` varchar(100) DEFAULT NULL,
PRIMARY KEY (`TokenID`),
UNIQUE KEY `TokenID` (`TokenID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
PHP类(ebaytoken.php):
<?php
class EbayToken {
//Set variables.
public $success = false; //Default.
public $messages = []; //All messages.
public $db_token = null; //The actuasl token.
private $string; //String to update the token.
private $access_token_expired = true; //Dfault to expired.
private $refresh_token_expired = true;
private $refresh_token_almost_expired = true; //Flag to display a warning message.
private $client_id = 'your_client_id';
private $secret = 'your_secret'; //API key. https://developer.ebay.com/my/keys
private $ru_name_value = 'your_ru';
private $scope = 'https://api.ebay.com/oauth/api_scope/sell.fulfillment';
private $base64_encoded_credentials = null; //Initialise this in a mo.
function __construct($string = null) {
//Save the string.
$this->string = $string;
//Ininitalise the credentials.
$this->base64_encoded_credentials = base64_encode($this->client_id . ':' . $this->secret);
//Get any existing token from db.
$this->get_token_from_db();
//Check if it's expired - or almost expired. If there is no token this will not do anything.
$this->check_db_token();
//Has the current token expired??
if(($this->access_token_expired == true) && ($this->refresh_token_expired == true)) {
//Uh oh. Gonna have to get a new token - or display instructions on how to. Has the user entered the URL string to parse?
if((isset($this->string)) && ($this->string != '')) {
$this->get_new_tokens($this->string);
} else {
$this->get_new_tokens_instructions();
}
} else if($this->access_token_expired == true) {
//Just the access token. Get a fresh one. If the refresh token has almost expired, display the instuctions.
if($this->refresh_token_almost_expired == true) {
$this->need_new_tokens_almost_instructions();
}
$this->refresh_token(); //Just the access token expired - go and refresh it using the refresh token.
} else {
//All fine. If the refresh token has almost expired, display the instructions.
if($this->refresh_token_almost_expired == true) {
$this->need_new_tokens_almost_instructions();
}
}
}
//Get the current token information from the DB. Should only be 1.
private function get_token_from_db() {
//Get token(s). Should only be 1. But loop anyhow.
$sql = "SELECT * FROM EbayTokens";
$res = @mysql_query($sql);
$count = 0;
if($res) {
$count = mysql_num_rows($res);
while ($rec = mysql_fetch_assoc($res)) {
$this->db_token = $rec;
}
$this->messages[] = '<span style="color:limegreen;"><strong>Access token loaded from database...</strong></span>';
} else {
$this->messages[] = '<span style="color:red;"><strong>No token found in database!</strong></span>';
}
return null;
}
//Has the access token expired?
private function check_db_token() {
//Do we even have a token from the db?
if($this->db_token != null) {
//Access token expired?
$now = new DateTime();
$now_plus_30_days = new DateTime();
$now_plus_30_days->add(DateInterval::createFromDateString('30 days'));
$date_created = DateTime::createFromFormat('Y-m-d H:i:s', $this->db_token['TokenCreated']);
$date_expires = DateTime::createFromFormat('Y-m-d H:i:s', $this->db_token['TokenCreated']); //Make a new object.
$date_expires->add(DateInterval::createFromDateString($this->db_token['TokenLifetime'] . ' seconds'));
//Refresh token expired?
$refresh_date_created = DateTime::createFromFormat('Y-m-d H:i:s', $this->db_token['RefreshTokenCreated']);
$refresh_date_expires = DateTime::createFromFormat('Y-m-d H:i:s', $this->db_token['RefreshTokenCreated']); //Make a new object.
$refresh_date_expires->add(DateInterval::createFromDateString($this->db_token['RefreshTokenLifetime'] . ' seconds'));
//Check access token.
$this->messages[] = 'Access token created on: ' . $date_created->format('d/m/Y H:i:s') . ', expires: ' . $date_expires->format('d/m/Y H:i:s');
if($date_expires < $now) {
$this->messages[] = ' <span style="color:red;"><strong>Access token expired!</strong></span>';
} else {
$this->messages[] = ' <span style="color:limegreen;"><strong>Access token valid!</strong></span>';
$this->access_token_expired = false;
}
//Check refresh token.
$this->messages[] = 'Refresh token created on: ' . $refresh_date_created->format('d/m/Y H:i:s') . ', expires: ' . $refresh_date_expires->format('d/m/Y H:i:s');
if($refresh_date_expires < $now) {
$this->messages[] = '<span style="color:red;"><strong>Refresh token expired!</strong></span>';
} else if($refresh_date_expires < $now_plus_30_days) {
$this->messages[] = ' <span style="color:darkorange;"><strong>Refresh token valid! But expires within 30 days. INFORM ADMIN TO GENERATE A NEW REFRESH TOKEN.</strong></span>';
$this->refresh_token_expired = false;
} else {
$this->messages[] = '<span style="color:limegreen;"><strong>Refresh token valid!</strong></span>';
$this->refresh_token_almost_expired = false;
$this->refresh_token_expired = false;
}
//Was it all ok?
if(($this->refresh_token_expired == false) && ($this->access_token_expired == false)) {
$this->messages[] = '<span style="color:limegreen;"><strong>All tokens valid!</strong></span>';
$this->success = true;
}
}
return null;
}
//Go and get a new token using the refresh token. Save it to the db.
private function refresh_token() {
$this->messages[] = 'OAUTH token expired - refreshing token...';
// $this->messages[] = 'Using refresh token: ' . $this->db_token['RefreshTokenValue'];
//Connect to Ebay API and refresh the existing oauth token.
$url_get_token = 'https://api.ebay.com/identity/v1/oauth2/token';
$port = 443;
$headers = array(
'Content-Type: application/x-www-form-urlencoded',
'Authorization: Basic ' . $this->base64_encoded_credentials
);
$payload = array(
'grant_type' => 'refresh_token',
'refresh_token' => $this->db_token['RefreshTokenValue'],
'scope=' . urlencode($this->scope),
);
$payload_string = http_build_query($payload);
//Setting the curl parameters.
$ch = curl_init();
curl_setopt($ch, CURLOPT_PORT, $port);
curl_setopt($ch, CURLOPT_URL, $url_get_token);
curl_setopt($ch, CURLOPT_POST, true);
// curl_setopt($ch, CURLOPT_SSLVERSION, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload_string);
$data = curl_exec($ch);
curl_close($ch);
//Convert the JSON result into array
$array_data = json_decode($data, true);
//Did we get an access token?
$access_token = null;
if((is_array($array_data)) && (isset($array_data['access_token']))) {
//Save the tokens to the database. Set variables.
$access_token = mysql_real_escape_string($array_data['access_token']);
$expires_in = mysql_real_escape_string($array_data['expires_in']);
$token_type = mysql_real_escape_string($array_data['token_type']);
//Update. This will only be run if there is already a token in the DB. So no need to truncate.
$now = new DateTime();
$now_mysql = $now->format('Y-m-d H:i:s');
$existing_token_id = $this->db_token['TokenID'];
$sql = sprintf("UPDATE EbayTokens SET TokenValue = '%s', TokenCreated = '%s', TokenLifetime = %s, TokenType = '%s' WHERE TokenID = %d", $access_token, $now_mysql, $expires_in, $token_type, $existing_token_id);
// $this->messages[] = 'SQL: ' . $sql;
if (@executeSQL($sql)) {
$this->messages[] = '<span style="color:limegreen;"><strong>Success! Token refreshed and saved to database.</strong></span>';
}
//Update the token in this object from the freshly saved data.
$this->get_token_from_db();
$this->check_db_token(); //Re-check - this will mark the success flag in this object.
} else {
$this->messages[] = '<span style="color:red;"><strong>Failed to get OAUTH token! Aborting</strong></span>.';
$this->messages[] = 'Reply was:' . '<br><pre>' . print_r($array_data) . '</pre>';
}
return null;
}
//Get new tokens using the string supplied.
private function get_new_tokens($string) {
//Parse the URL string supplied and get the 'code'.
$auth_code = null;
$parameters = parse_url($string);
$query_array = explode('&', $parameters['query']);
//Loop through and get code. Just in case the 'code' moves to another position.
foreach ($query_array as $parameter) {
$parameter_array = explode('=', $parameter);
if($parameter_array[0] == 'code') {
$auth_code = $parameter_array[1];
break; //Got what we want.
}
}
/***********************************************************************/
$this->messages[] = "Getting eBay Oauth token using URL string...";
$this->messages[] = 'Using auth code: ' . $auth_code;
//Connect to Ebay API and get an oath using authorisation code.
$url_get_token = 'https://api.ebay.com/identity/v1/oauth2/token';
$port = 443;
$headers = array(
'Content-Type: application/x-www-form-urlencoded',
'Authorization: Basic ' . $this->base64_encoded_credentials
);
$payload = array(
'grant_type' => 'authorization_code',
'code' => urldecode($auth_code), //Get from step one.
'redirect_uri' => $this->ru_name_value, //Same as used in part one.
);
$payload_string = http_build_query($payload);
//Setting the curl parameters.
$ch = curl_init();
curl_setopt($ch, CURLOPT_PORT, $port);
curl_setopt($ch, CURLOPT_URL, $url_get_token);
curl_setopt($ch, CURLOPT_POST, true);
// curl_setopt($ch, CURLOPT_SSLVERSION, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload_string);
$data = curl_exec($ch);
curl_close($ch);
//Convert the JSON result into array
$array_data = json_decode($data, true);
//Did we get an access token?
$access_token = null;
if((is_array($array_data)) && (isset($array_data['access_token']))) {
//Save the tokens to the database. Set variables.
$access_token = mysql_real_escape_string($array_data['access_token']);
$expires_in = mysql_real_escape_string($array_data['expires_in']);
$refresh_token = mysql_real_escape_string($array_data['refresh_token']);
$refresh_token_expires_in = mysql_real_escape_string($array_data['refresh_token_expires_in']);
$token_type = mysql_real_escape_string($array_data['token_type']);
//Truncate and then insert. There may or may not be an existing token in the db.
$this->truncate_db();
$now = new DateTime();
$now_mysql = $now->format('Y-m-d H:i:s');
$sql = sprintf("INSERT INTO EbayTokens SET TokenValue = '%s', TokenCreated = '%s', TokenLifetime = %d, RefreshTokenValue = '%s', RefreshTokenCreated = '%s', RefreshTokenLifetime = %d, TokenType = '%s' ", $access_token, $now_mysql, $expires_in, $refresh_token, $now_mysql, $refresh_token_expires_in, $token_type);
if (@executeSQL($sql)) {
$this->messages[] = '<span style="color:limegreen;"><strong>Success! New token aquired and saved to database.</strong></span>';
} else {
$this->messages[] = '<span style="color:red;"><strong>Error saving new token to database!</strong></span>';
}
//Update the token in the object from the freshly saved data.
$this->get_token_from_db();
$this->check_db_token(); //Re-check - this will mark the success flag.
} else {
$this->messages[] = '<span style="color:red;"><strong>Failed to get OAUTH token! Aborting</strong></span>.';
$this->messages[] = 'Reply was:' . '<br><pre>' . print_r($array_data) . '</pre>';
}
return null;
}
//Instructions to get a new refresh token.
private function get_new_tokens_instructions() {
$this->messages[] = '<span style="color:red;">Tokens expired! Admin action required</span>';
$this->messages[] = "In order to get a fresh oauth token (and more importantly a refresh token), click on the URL below (it will open in a new window) and login as.";
//Connect to Ebay API and get consent. The authorization code grant flow. https://developer.ebay.com/api-docs/static/oauth-authorization-code-grant.html
$url_get_consent = 'https://auth.ebay.com/oauth2/authorize';
$payload = array(
'client_id=' . $this->client_id,
'redirect_uri=' . $this->ru_name_value,
'response_type=code',
'scope=' . urlencode($this->scope),
);
$payload_string = implode('&', $payload);
$url_get_consent_full = $url_get_consent . '?' . $payload_string;
$this->messages[] = 'URL: <a href="' . $url_get_consent_full . '" target="_blank">' . $url_get_consent_full . '</a><br>';
$this->messages[] = "Once you have completed the login and see the window saying you can close the page, <strong>copy the URL</strong>. It will contain a 'code' parameter.";
$this->messages[] = "Insert the coppied URL in the form below and click submit. The new code will be used and a new oauth and refresh token will be obtained and stored in the database.";
$this->messages[] = '
<form>
URL string:
<input type="text" name="string" size="50">
<input type="submit" value="Submit">
</form>
';
return null;
}
//Instructions to get a new refresh token - refresh token has ALMOST expired.
private function need_new_tokens_almost_instructions() {
$this->messages[] = '<span style="color:darkorange;">Tokens ALMOST expired! Admin action required</span>';
$this->messages[] = "In order to get a fresh oauth token (and more importantly a refresh token), click on the URL below (it will open in a new window) and login.";
//Connect to Ebay API and get consent. The authorization code grant flow. https://developer.ebay.com/api-docs/static/oauth-authorization-code-grant.html
$url_get_consent = 'https://auth.ebay.com/oauth2/authorize';
$payload = array(
'client_id=' . $this->client_id,
'redirect_uri=' . $this->ru_name_value,
'response_type=code',
'scope=' . urlencode($this->scope),
);
$payload_string = implode('&', $payload);
$url_get_consent_full = $url_get_consent . '?' . $payload_string;
$this->messages[] = 'URL: <a href="' . $url_get_consent_full . '" target="_blank">' . $url_get_consent_full . '</a><br>';
$this->messages[] = "Once you have completed the login and see the window saying you can close the page, <strong>copy the URL</strong>. It will contain a 'code' parameter.";
$this->messages[] = "Insert the coppied URL in the form below and click submit. The new code will be used and a new oauth and refresh token will be obtained and stored in the database.";
$this->messages[] = '
<form>
URL string:
<input type="text" name="string" size="50">
<input type="submit" value="Submit">
</form>
';
return null;
}
//Delete any tokens from the database. Use cautiously.
private function truncate_db() {
$sql = "TRUNCATE TABLE EbayTokens";
if (@executeSQL($sql)) {
$this->messages[] = '<span style="color:limegreen;"><strong>Existing tokens deleted from database.</strong></span>';
}
return null;
}
}
?>
还有一个测试/使用的小脚本:
<?php
require_once("classes/ebaytoken.php");
$thispage = new Page();
//Is there a string in the $_GET array? If so, feed it into the constructor.
$string = null;
if((isset($_GET['string'])) && ($_GET['string'] != '')) {
$string = $_GET['string'];
}
$token = new EbayToken($string);
echo "<h3>Current eBay Tokens</h3>";
$messages = $token->messages;
if(count($messages) > 0) {
echo '<ul>';
foreach ($messages as $message) {
echo '<ul>' . $message . '</ul>';
}
echo '</ul>';
}
//Is the token valid?
if($token->success == true) {
get_orders($token->db_token);
}
//Get ebay orders.
function get_orders($token_data) {
echo "<h3>Getting Ebay Orders</h3>";
//Start the main request now we have the token. https://developer.ebay.com/api-docs/sell/static/orders/discovering-unfulfilled-orders.html
$url_get_orders = 'https://api.ebay.com/sell/fulfillment/v1/order';
$port = 443;
$headers = array(
'Authorization: Bearer ' . $token_data['TokenValue'],
'X-EBAY-C-MARKETPLACE-ID: EBAY_GB',
);
$payload = array(
'filter=orderfulfillmentstatus:' . urlencode('{NOT_STARTED|IN_PROGRESS}'),
'limit=100',
'offset=0',
);
$payload_string = implode('&', $payload);
$url_get_orders_full = $url_get_orders . '?' . $payload_string;
//Setting the curl parameters.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url_get_orders_full); //For 'get', add query string to end of URL.
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300);
$data = curl_exec($ch);
curl_close($ch);
//Convert the JSON result into array
$array_data = json_decode($data, true);
print_r('<pre>');
print_r($array_data);
print_r('</pre>');
return null;
}
?>