Coinigy V2 授权问题 API
Issue with authorization on Coinigy V2 API
我一直在做一个项目,我曾经使用 v1 api 来创造新事物并且喜欢 API。现在问题出在新的 v2 API 上,我在尝试使用带有 hmac_sha256 签名的私有 API 时遇到了问题。我最初联系了 coinigy 支持,但运气不好无法让它完全正常工作(他们确实提供了帮助,但从未解决问题,这很奇怪)。我用 C# 构建了一个简单的测试项目,以使用他们的 api 文档执行私人调用。
program.cs:
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace coinigy_example
{
class Program
{
static void Main(string[] args)
{
string api_key = "API_KEY";
string api_secret = "API_SECRET";
CoinigyApiPrivateCall call = new CoinigyApiPrivateCall(api_key, api_decret);
string data = call.HttpPostRequest("private/exchanges/" + "BINA" + "/markets/" + "BTC" + "/" + "LTC" + "/ticker", "", null, "GET");
string body = null;
call.xcoinApiCall("private/exchanges/" + "BINA" + "/markets/" + "BTC" + "/" + "LTC" + "/ticker", "", ref body);
try
{
JObject j = JObject.Parse(data);
TickerDataCoinigy tt = new TickerDataCoinigy();
tt.volume = (string)j["volume"];
tt.last = (string)j["last"];
tt.high = (string)j["high"];
tt.low = (string)j["low"];
tt.ask = (string)j["ask"];
tt.bid = (string)j["bid"];
Console.WriteLine("Binance, BTC-LTC ticker data:");
Console.WriteLine("Volume: " + tt.volume);
Console.WriteLine("Last: " + tt.last);
Console.WriteLine("High: " + tt.high);
Console.WriteLine("Low: " + tt.low);
Console.WriteLine("ask: " + tt.ask);
Console.WriteLine("bid: " + tt.bid);
}
catch(Exception i)
{
Console.WriteLine("");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(data);
Console.ForegroundColor = ConsoleColor.White;
}
Console.ReadLine();
}
}
public class TickerDataCoinigy
{
public string volume;
public string last;
public string high;
public string low;
public string ask;
public string bid;
}
}
以及私人通话的多个版本(以查看调用 api 的不同方式是否可行)。
CoinigyApiPrivateCall.cs
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace coinigy_example
{
public class CoinigyApiPrivateCall
{
private string api_key;
private string api_secret;
public CoinigyApiPrivateCall(string api_key, string api_secret)
{
this.api_key = api_key;
this.api_secret = api_secret;
}
public static double ConvertToUnixTimestamp(DateTime date)
{
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan diff = date.ToUniversalTime() - origin;
return Math.Floor(diff.TotalMilliseconds);
}
private string Hash_HMAC(string sKey, string sData)
{
byte[] rgbyKey = Encoding.ASCII.GetBytes(sKey);
using (var hmacsha256 = new HMACSHA256(rgbyKey))
{
byte[] inf = hmacsha256.ComputeHash(Encoding.ASCII.GetBytes(sData));
return (ByteToString(inf));
}
}
private string ByteToString(byte[] rgbyBuff)
{
string sHexStr = "";
for (int nCnt = 0; nCnt < rgbyBuff.Length; nCnt++)
{
sHexStr += rgbyBuff[nCnt].ToString("x2"); // Hex format
}
return (sHexStr);
}
private byte[] StringToByte(string sStr)
{
byte[] rgbyBuff = Encoding.ASCII.GetBytes(sStr);
return (rgbyBuff);
}
public string HttpPostRequest(string url, string au, List<KeyValuePair<string, string>> postdata, string httpType)
{
var client = new HttpClient();
//client.DefaultRequestHeaders.Add("User-Agent", ua);
//client.DefaultRequestHeaders.Add("X-API-KEY", api_key);
//client.DefaultRequestHeaders.Add("X-API-SECRET", api_secret);
string time = Convert.ToString(ConvertToUnixTimestamp(DateTime.Now.ToUniversalTime()));
FormUrlEncodedContent content = null;
string data = null;
if (postdata != null)
{
content = new FormUrlEncodedContent(postdata);
var output = Newtonsoft.Json.JsonConvert.SerializeObject(postdata);
data = api_key + time + httpType.ToUpper() + "/api/v2/" + url + output;
}
else
{
data = api_key + time + httpType.ToUpper() + "/api/v2/" + url;
}
string sign = Hash_HMAC(api_secret, data);
client.DefaultRequestHeaders.Add("X-API-SIGN", sign);
client.DefaultRequestHeaders.Add("X-API-TIMESTAMP", time);
HttpResponseMessage response = null;
if (httpType.ToUpper() == "POST")
{
response = client.PostAsync("https://api.coinigy.com/api/v2/" + url, content).Result;
}
if (httpType.ToUpper() == "GET")
{
response = client.GetAsync("https://api.coinigy.com/api/v2/" + url).Result;
}
if (httpType.ToUpper() == "PUT")
{
response = client.PutAsync("https://api.coinigy.com/api/v2/" + url, content).Result;
}
if (httpType.ToUpper() == "DELETE")
{
response = client.DeleteAsync("https://api.coinigy.com/api/v2/" + url).Result;
}
return response.IsSuccessStatusCode
? response.Content.ReadAsStringAsync().Result
: "ERROR:" + response.StatusCode + " " + response.ReasonPhrase + " | " + response.RequestMessage;
}
public JObject xcoinApiCall(string sEndPoint, string sParams, ref string sRespBodyData)
{
string sAPI_Sign = "";
string sPostData = sParams;
string sHMAC_Key = "";
string sHMAC_Data = "";
string sResult = "";
double nNonce = 0;
HttpStatusCode nCode = 0;
sPostData += "&endpoint=" + Uri.EscapeDataString(sEndPoint);
try
{
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://api.coinigy.com/api/v2/" + sEndPoint);
byte[] rgbyData = Encoding.ASCII.GetBytes(sPostData);
nNonce = ConvertToUnixTimestamp(DateTime.Now.ToUniversalTime());
sHMAC_Key = this.api_secret;
sHMAC_Data = api_key + nNonce.ToString() + "GET" + "/api/v2/" + sEndPoint;
//sHMAC_Data = sEndPoint + (char)0 + sPostData + (char)0 + nNonce.ToString();
sResult = Hash_HMAC(sHMAC_Key, sHMAC_Data);
//sAPI_Sign = Convert.ToBase64String(StringToByte(sResult));
sAPI_Sign = sResult;
Request.Headers.Add("X-API-SIGN", sAPI_Sign);
Request.Headers.Add("X-API-TIMESTAMP", nNonce.ToString());
Request.Method = "GET";
Request.ContentType = "application/x-www-form-urlencoded";
Request.UserAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36";
/*Request.ContentLength = rgbyData.Length;
using (var stream = Request.GetRequestStream())
{
stream.Write(rgbyData, 0, rgbyData.Length);
} */
var Response = (HttpWebResponse)Request.GetResponse();
sRespBodyData = new StreamReader(Response.GetResponseStream()).ReadToEnd();
return (JObject.Parse(sRespBodyData));
}
catch (WebException webEx)
{
using (HttpWebResponse Response = (HttpWebResponse)webEx.Response)
{
nCode = Response.StatusCode;
using (StreamReader reader = new StreamReader(Response.GetResponseStream()))
{
sRespBodyData = reader.ReadToEnd();
try
{
return (JObject.Parse(sRespBodyData));
}
catch(Exception i)
{
}
}
}
}
return (null);
}
}
}
如果有人对此有任何了解可以提供帮助,我将不胜感激。
编辑:我使用了 Joe 的代码来查看是否可以修复未经授权的问题,我得到了这个结果:
{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content:
System.Net.Http.StreamContent, Headers:
{
Date: Sun, 29 Jul 2018 19:19:36 GMT
Content-Length: 0
}}
我正在使用此代码执行 http 调用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Coinigy_v2_api_2018.Functions;
using System.Net.Http;
namespace Coinigy_v2_api_test
{
class Program
{
static void Main(string[] args)
{
ApiRequest req = new ApiRequest();
req.BaseUrl = "https://api.coinigy.com";
req.Body = "";
req.Method = "GET";
req.Secret = "secret";
req.Key = "key";
req.Endpoint = "/api/v2/private/exchanges";
string signature = req.Signature;
HttpResponseMessage response = null;
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("X-API-SIGN", signature);
client.DefaultRequestHeaders.Add("X-API-TIMESTAMP", req.Timestamp);
response = client.GetAsync(req.BaseUrl + req.Endpoint).Result;
}
string r = null;
if (response.IsSuccessStatusCode)
{
r = response.Content.ReadAsStringAsync().Result;
}
Console.WriteLine(r);
Console.ReadLine();
}
}
}
再次感谢您!
API 文档可在此处找到:https://api.coinigy.com/api/v2/docs/#/
2019-08-28:最新更新是端点在生成签名时必须要求查询参数未编码。
首先要检查的是确保您使用的是 V2 api key/secret。旧的 V1 键不适用于 V2 api。如果您升级订阅,您可能需要生成一个新密钥才能生效。
这里有一个 class 如果不能解决问题的话应该会有所帮助:
public class ApiRequest
{
public string BaseUrl { get; set; }
public string Endpoint { get; set; }
public string Key { get; set; }
public string Secret { get; set; }
public string Method { get; set; }
public string Body { get; set; }
public string Timestamp { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
/// <summary>
/// Each API request needs to be signed so the sender can be identified.
/// This property generates the signature based on the current request.
/// </summary>
public string Signature
{
get
{
var asciiEncoding = new ASCIIEncoding();
var hmac = new HMACSHA256(asciiEncoding.GetBytes(Secret));
string signature = Key + Timestamp + Method.ToUpper() + Endpoint + (Body ?? string.Empty);
byte[] signatureBytes = asciiEncoding.GetBytes(signature);
byte[] hashedSignatureBytes = hmac.ComputeHash(signatureBytes);
string hexSignature = string.Join(string.Empty, Array.ConvertAll(hashedSignatureBytes, hb => hb.ToString("X2")));
return hexSignature;
}
}
}
如果正确设置这些值,您应该能够生成正确的签名。
对于参数值,从这样的开始,然后与我生成的签名进行比较,以确保您的签名功能正常工作:
BaseUrl : https://api.coinigy.com
Endpoint : /api/v2/private/exchanges?pythagoreanTheorem=a%5E2%2Bb%5E2%3Dc%5E2
Key : keykeykeykeykeykeykeykeykeykeyke
Secret : secretsecretsecretsecretsecretse
Method : GET
Timestamp : 1532718830 (which is 2018-07-27T19:13:50.6694555Z)
Body : (empty string)
Signature : B618C0B3C92632C701D7CEFC00AC9C8A0771989B21E00D61D4945F79239D2F87
这是将执行整个过程的奖励 python3 版本:https://gist.github.com/phillijw/1f78c8bafdce3a71a0b2ef9d4f5942a1
我一直在做一个项目,我曾经使用 v1 api 来创造新事物并且喜欢 API。现在问题出在新的 v2 API 上,我在尝试使用带有 hmac_sha256 签名的私有 API 时遇到了问题。我最初联系了 coinigy 支持,但运气不好无法让它完全正常工作(他们确实提供了帮助,但从未解决问题,这很奇怪)。我用 C# 构建了一个简单的测试项目,以使用他们的 api 文档执行私人调用。
program.cs:
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace coinigy_example
{
class Program
{
static void Main(string[] args)
{
string api_key = "API_KEY";
string api_secret = "API_SECRET";
CoinigyApiPrivateCall call = new CoinigyApiPrivateCall(api_key, api_decret);
string data = call.HttpPostRequest("private/exchanges/" + "BINA" + "/markets/" + "BTC" + "/" + "LTC" + "/ticker", "", null, "GET");
string body = null;
call.xcoinApiCall("private/exchanges/" + "BINA" + "/markets/" + "BTC" + "/" + "LTC" + "/ticker", "", ref body);
try
{
JObject j = JObject.Parse(data);
TickerDataCoinigy tt = new TickerDataCoinigy();
tt.volume = (string)j["volume"];
tt.last = (string)j["last"];
tt.high = (string)j["high"];
tt.low = (string)j["low"];
tt.ask = (string)j["ask"];
tt.bid = (string)j["bid"];
Console.WriteLine("Binance, BTC-LTC ticker data:");
Console.WriteLine("Volume: " + tt.volume);
Console.WriteLine("Last: " + tt.last);
Console.WriteLine("High: " + tt.high);
Console.WriteLine("Low: " + tt.low);
Console.WriteLine("ask: " + tt.ask);
Console.WriteLine("bid: " + tt.bid);
}
catch(Exception i)
{
Console.WriteLine("");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(data);
Console.ForegroundColor = ConsoleColor.White;
}
Console.ReadLine();
}
}
public class TickerDataCoinigy
{
public string volume;
public string last;
public string high;
public string low;
public string ask;
public string bid;
}
}
以及私人通话的多个版本(以查看调用 api 的不同方式是否可行)。
CoinigyApiPrivateCall.cs
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace coinigy_example
{
public class CoinigyApiPrivateCall
{
private string api_key;
private string api_secret;
public CoinigyApiPrivateCall(string api_key, string api_secret)
{
this.api_key = api_key;
this.api_secret = api_secret;
}
public static double ConvertToUnixTimestamp(DateTime date)
{
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan diff = date.ToUniversalTime() - origin;
return Math.Floor(diff.TotalMilliseconds);
}
private string Hash_HMAC(string sKey, string sData)
{
byte[] rgbyKey = Encoding.ASCII.GetBytes(sKey);
using (var hmacsha256 = new HMACSHA256(rgbyKey))
{
byte[] inf = hmacsha256.ComputeHash(Encoding.ASCII.GetBytes(sData));
return (ByteToString(inf));
}
}
private string ByteToString(byte[] rgbyBuff)
{
string sHexStr = "";
for (int nCnt = 0; nCnt < rgbyBuff.Length; nCnt++)
{
sHexStr += rgbyBuff[nCnt].ToString("x2"); // Hex format
}
return (sHexStr);
}
private byte[] StringToByte(string sStr)
{
byte[] rgbyBuff = Encoding.ASCII.GetBytes(sStr);
return (rgbyBuff);
}
public string HttpPostRequest(string url, string au, List<KeyValuePair<string, string>> postdata, string httpType)
{
var client = new HttpClient();
//client.DefaultRequestHeaders.Add("User-Agent", ua);
//client.DefaultRequestHeaders.Add("X-API-KEY", api_key);
//client.DefaultRequestHeaders.Add("X-API-SECRET", api_secret);
string time = Convert.ToString(ConvertToUnixTimestamp(DateTime.Now.ToUniversalTime()));
FormUrlEncodedContent content = null;
string data = null;
if (postdata != null)
{
content = new FormUrlEncodedContent(postdata);
var output = Newtonsoft.Json.JsonConvert.SerializeObject(postdata);
data = api_key + time + httpType.ToUpper() + "/api/v2/" + url + output;
}
else
{
data = api_key + time + httpType.ToUpper() + "/api/v2/" + url;
}
string sign = Hash_HMAC(api_secret, data);
client.DefaultRequestHeaders.Add("X-API-SIGN", sign);
client.DefaultRequestHeaders.Add("X-API-TIMESTAMP", time);
HttpResponseMessage response = null;
if (httpType.ToUpper() == "POST")
{
response = client.PostAsync("https://api.coinigy.com/api/v2/" + url, content).Result;
}
if (httpType.ToUpper() == "GET")
{
response = client.GetAsync("https://api.coinigy.com/api/v2/" + url).Result;
}
if (httpType.ToUpper() == "PUT")
{
response = client.PutAsync("https://api.coinigy.com/api/v2/" + url, content).Result;
}
if (httpType.ToUpper() == "DELETE")
{
response = client.DeleteAsync("https://api.coinigy.com/api/v2/" + url).Result;
}
return response.IsSuccessStatusCode
? response.Content.ReadAsStringAsync().Result
: "ERROR:" + response.StatusCode + " " + response.ReasonPhrase + " | " + response.RequestMessage;
}
public JObject xcoinApiCall(string sEndPoint, string sParams, ref string sRespBodyData)
{
string sAPI_Sign = "";
string sPostData = sParams;
string sHMAC_Key = "";
string sHMAC_Data = "";
string sResult = "";
double nNonce = 0;
HttpStatusCode nCode = 0;
sPostData += "&endpoint=" + Uri.EscapeDataString(sEndPoint);
try
{
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://api.coinigy.com/api/v2/" + sEndPoint);
byte[] rgbyData = Encoding.ASCII.GetBytes(sPostData);
nNonce = ConvertToUnixTimestamp(DateTime.Now.ToUniversalTime());
sHMAC_Key = this.api_secret;
sHMAC_Data = api_key + nNonce.ToString() + "GET" + "/api/v2/" + sEndPoint;
//sHMAC_Data = sEndPoint + (char)0 + sPostData + (char)0 + nNonce.ToString();
sResult = Hash_HMAC(sHMAC_Key, sHMAC_Data);
//sAPI_Sign = Convert.ToBase64String(StringToByte(sResult));
sAPI_Sign = sResult;
Request.Headers.Add("X-API-SIGN", sAPI_Sign);
Request.Headers.Add("X-API-TIMESTAMP", nNonce.ToString());
Request.Method = "GET";
Request.ContentType = "application/x-www-form-urlencoded";
Request.UserAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36";
/*Request.ContentLength = rgbyData.Length;
using (var stream = Request.GetRequestStream())
{
stream.Write(rgbyData, 0, rgbyData.Length);
} */
var Response = (HttpWebResponse)Request.GetResponse();
sRespBodyData = new StreamReader(Response.GetResponseStream()).ReadToEnd();
return (JObject.Parse(sRespBodyData));
}
catch (WebException webEx)
{
using (HttpWebResponse Response = (HttpWebResponse)webEx.Response)
{
nCode = Response.StatusCode;
using (StreamReader reader = new StreamReader(Response.GetResponseStream()))
{
sRespBodyData = reader.ReadToEnd();
try
{
return (JObject.Parse(sRespBodyData));
}
catch(Exception i)
{
}
}
}
}
return (null);
}
}
}
如果有人对此有任何了解可以提供帮助,我将不胜感激。
编辑:我使用了 Joe 的代码来查看是否可以修复未经授权的问题,我得到了这个结果:
{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content:
System.Net.Http.StreamContent, Headers:
{
Date: Sun, 29 Jul 2018 19:19:36 GMT
Content-Length: 0
}}
我正在使用此代码执行 http 调用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Coinigy_v2_api_2018.Functions;
using System.Net.Http;
namespace Coinigy_v2_api_test
{
class Program
{
static void Main(string[] args)
{
ApiRequest req = new ApiRequest();
req.BaseUrl = "https://api.coinigy.com";
req.Body = "";
req.Method = "GET";
req.Secret = "secret";
req.Key = "key";
req.Endpoint = "/api/v2/private/exchanges";
string signature = req.Signature;
HttpResponseMessage response = null;
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("X-API-SIGN", signature);
client.DefaultRequestHeaders.Add("X-API-TIMESTAMP", req.Timestamp);
response = client.GetAsync(req.BaseUrl + req.Endpoint).Result;
}
string r = null;
if (response.IsSuccessStatusCode)
{
r = response.Content.ReadAsStringAsync().Result;
}
Console.WriteLine(r);
Console.ReadLine();
}
}
}
再次感谢您!
API 文档可在此处找到:https://api.coinigy.com/api/v2/docs/#/
2019-08-28:最新更新是端点在生成签名时必须要求查询参数未编码。
首先要检查的是确保您使用的是 V2 api key/secret。旧的 V1 键不适用于 V2 api。如果您升级订阅,您可能需要生成一个新密钥才能生效。
这里有一个 class 如果不能解决问题的话应该会有所帮助:
public class ApiRequest
{
public string BaseUrl { get; set; }
public string Endpoint { get; set; }
public string Key { get; set; }
public string Secret { get; set; }
public string Method { get; set; }
public string Body { get; set; }
public string Timestamp { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
/// <summary>
/// Each API request needs to be signed so the sender can be identified.
/// This property generates the signature based on the current request.
/// </summary>
public string Signature
{
get
{
var asciiEncoding = new ASCIIEncoding();
var hmac = new HMACSHA256(asciiEncoding.GetBytes(Secret));
string signature = Key + Timestamp + Method.ToUpper() + Endpoint + (Body ?? string.Empty);
byte[] signatureBytes = asciiEncoding.GetBytes(signature);
byte[] hashedSignatureBytes = hmac.ComputeHash(signatureBytes);
string hexSignature = string.Join(string.Empty, Array.ConvertAll(hashedSignatureBytes, hb => hb.ToString("X2")));
return hexSignature;
}
}
}
如果正确设置这些值,您应该能够生成正确的签名。
对于参数值,从这样的开始,然后与我生成的签名进行比较,以确保您的签名功能正常工作:
BaseUrl : https://api.coinigy.com
Endpoint : /api/v2/private/exchanges?pythagoreanTheorem=a%5E2%2Bb%5E2%3Dc%5E2
Key : keykeykeykeykeykeykeykeykeykeyke
Secret : secretsecretsecretsecretsecretse
Method : GET
Timestamp : 1532718830 (which is 2018-07-27T19:13:50.6694555Z)
Body : (empty string)
Signature : B618C0B3C92632C701D7CEFC00AC9C8A0771989B21E00D61D4945F79239D2F87
这是将执行整个过程的奖励 python3 版本:https://gist.github.com/phillijw/1f78c8bafdce3a71a0b2ef9d4f5942a1