Coinbase Api Java POST request "Invalid Signature"



我正在尝试向coinbase沙箱端点发送POST请求。在签署请求时,我总是收到"无效签名"的回复。coinbase似乎需要对JSON消息进行base64编码,并将其作为签名的一部分发送。我是POST请求的新手,以前从未签署过消息。有人能告诉我我做错了什么吗。我已经在这个问题上呆了一个星期了,所以任何意见都非常感谢。

我的代码的相关部分在下面

public void postOrder() throws InvalidKeyException, NoSuchAlgorithmException, CloneNotSupportedException, ClientProtocolException, IOException {
String message = "{ n"+
" "size":"1.00", n"+
" "price":"0.80", n"+
" "side":"buy", n"+
" "product_id":"BTC-USD" n"+
"}"; 
JSONObject json = new JSONObject(message);
message = json.toString();
try
{
String timestamp= Instant.now().getEpochSecond()+"";
String accessSign = getAccess(timestamp,"POST","/orders",message);
String apiKey = properties.getProperty("key");
String passphrase = properties.getProperty("passphrase");
URL url = new URL("https://api-public.sandbox.pro.coinbase.com/orders");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setDoOutput(true); 
connection.setRequestProperty("accept", "application/json");
connection.setRequestProperty("content-type", "application/json; charset=UTF-8");
connection.setRequestProperty("CB-ACCESS-KEY", apiKey);
connection.setRequestProperty("CB-ACCESS-SIGN", accessSign);
connection.setRequestProperty("CB-ACCESS-TIMESTAMP", timestamp);
connection.setRequestProperty("CB-ACCESS-PASSPHRASE", passphrase);
connection.setRequestProperty("User-Agent", "Java Client"); 
try { 
connection.getOutputStream().write(message.getBytes("UTF-8"));
OutputStream output = connection.getOutputStream(); 
output.write(param.getBytes("UTF-8"));
} catch (Exception e) {
System.out.println(e.getMessage());
}
String status = connection.getResponseMessage();
System.out.println("STATUS: "+status);  
}catch(Exception e) {
System.out.println(e.getMessage());
}
return;
}

private String getAccess(String timestamp, String method, String path, String param) throws NoSuchAlgorithmException, InvalidKeyException, CloneNotSupportedException, IllegalStateException, UnsupportedEncodingException {
String secretKeyString = properties.getProperty("secret");
String prehash = timestamp+method+path+param;
byte[] secretKeyDecoded = Base64.getDecoder().decode(secretKeyString);
SecretKey secretKey = new SecretKeySpec(secretKeyDecoded, "HmacSHA256");
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
hmacSha256.init(secretKey);
return Base64.getEncoder().encodeToString(hmacSha256.doFinal(prehash.getBytes()));
}

我能够使用javax.crypto.*库函数实现这一点。我所做的改变是

  • 为沙箱获取API密钥
  • 为了对签名进行编码,我明确使用了UTF_8

下面是我使用Coinbase沙箱API_KEY-的代码

public String getCoinbaseHeaderSignature(
String timeStamp, 
String method,
String requestPath,
String body
) throws NoSuchAlgorithmException, InvalidKeyException {
String data = timeStamp + method.toUpperCase() + requestPath + body;
byte[] key = Base64.getDecoder().decode(API_KEY);
SecretKey keySpec = new SecretKeySpec(key, "HmacSHA256");
// Get HmacSHA256 instance 
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(keySpec);
return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes(StandardCharsets.UTF_8)));
}

有关更多详细信息,请参阅文档https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-key-authentication

在我的例子中,我使用了gdax-java示例。我通过从时间戳中删除十进制值来解决这个问题,这意味着我只使用了时间戳值的整数部分。

最新更新