如何使用 Dart 签署 Binance HTTP 请求

Posted

技术标签:

【中文标题】如何使用 Dart 签署 Binance HTTP 请求【英文标题】:How to sign a Binance HTTP request using Dart 【发布时间】:2019-08-14 00:01:34 【问题描述】:

当我尝试发出请求时,我收到以下错误消息:

code: -1100, 
msg: Illegal characters found in parameter 'signature'; legal range is '^[A-Fa-f0-9]64$'

币安 API 链接:https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md

正在向https://api.binance.com/api/v3/account 发出请求。查询参数只是时间戳,因为它是必需的。

我 100% 确定我签署消息的方式有问题。我敢肯定,因为它包含像“+-/_=”这样的字符,显然是不允许的。错误一定是在代码的中间部分,但我似乎无法弄清楚。

我已经浏览了以下网站:

Signing a message with hmac and sha256 in dart

Flutter (Dart 2) accessing twitter GET api

Binance API Signature with Google Scripts

Hmac sha1 and base 64 encoding in dart

String baseUrl = 'https://api.binance.com/api/v3/account';
int timeStamp = DateTime.now().millisecondsSinceEpoch;
String queryParams = 'timestamp=' + timeStamp.toString();
String secret = 'SECRET_KEY_HERE';

List<int> messageBytes = utf8.encode(queryParams);
List<int> key = base64.decode(secret);
Hmac hmac = new Hmac(sha256, key);
Digest digest = hmac.convert(messageBytes);
String signature = base64.encode(digest.bytes);
String url = baseUrl + "?" + "signature=" + signature + "&" + queryParams;

var response = await http.get(
    url,
    headers: 
      "Accept": "application/json",
      "HTTP_ACCEPT_LANGUAGE": "en-US",
      "Accept-Language": "en-US",
      "X-MBX-APIKEY": "API_KEY_HERE"
    
);

print(response.body);

编辑 - 工作签名

String baseUrl = 'https://api.binance.com/api/v3/account?';
int timeStamp = DateTime.now().millisecondsSinceEpoch;
String queryParams = 'recvWindow=5000' + '&timestamp=' + timeStamp.toString();
String secret = 'SECRET_KEY_HERE';

List<int> messageBytes = utf8.encode(queryParams);
List<int> key = utf8.encode(secret);
Hmac hmac = new Hmac(sha256, key);
Digest digest = hmac.convert(messageBytes);
String signature = hex.encode(digest.bytes);
String url = baseUrl + queryParams + "&signature=" + signature;

var response = await http.get(
  url,
  headers: 
    "Accept": "application/json",
    "HTTP_ACCEPT_LANGUAGE": "en-US",
    "Accept-Language": "en-US",
    "X-MBX-APIKEY": "API_KEY_HERE"
  
);

print(response.body);

【问题讨论】:

'+-/' 是 base64 的一种变体,您可能希望使用 URL 安全变体 en.wikipedia.org/wiki/Base64#URL_applications 使用 api.dartlang.org/stable/1.24.3/dart-convert/Base64Codec/… 您好,谢谢您的回复,我明白您的意思了。我试过这样做 Base64Codec.urlSafe().encode(digest.bytes) 而不是 base64.encode(digest.bytes)Base64Codec.urlSafe().decode(secret) 而不是 base64.decode(secret),但它不起作用。 Base64Codec 仍然返回不需要的字符,例如 _。 我也试过使用base64Url.decode(secret)base64Url.encode(digest.bytes)base64Decode(secret)base64Encode(digest.bytes)base64.decode(secret)base64UrlEncode(digest.bytes)base64.encode(digest.bytes)Base64Encoder.urlSafe().convert(digest.bytes) 和@987654345 Base64Encoder(digest.bytes).convert()。它们都不起作用。这就是我能找到的所有 Base64 和 base64 编码/解码器。问题总是一样的 我还注意到,对于每个编码器/解码器,我使用的最后一个字符是 =,这也是一个问题,因为 = 不是一个允许的字符 我找到了这个api.dartlang.org/stable/2.2.0/dart-core/Uri/…。方法encodeComponent() 进行百分比编码。但这仍然不起作用,因为 % 也是一个不需要的字符。 【参考方案1】:

我再次得到错误: "code":-1022,"msg":"此请求的签名无效。"

import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart'
as http;
import 'package:convert/convert.dart';

class Binance 
  static void test() async 
    String baseUrl = 'api.binance.com';
    String path = '/api/v3/account';
    int timeStamp = DateTime.now().millisecondsSinceEpoch;
    String queryParams =
      '?recvWindow=5000' + '&timestamp=' + timeStamp.toString();
    String secret =
      'SECRET_KEY_HERE';
    List < int > messageBytes = utf8.encode(queryParams);
    List < int > key = utf8.encode(secret);
    Hmac hmac = new Hmac(sha256, key);
    Digest digest = hmac.convert(messageBytes);
    String signature = hex.encode(digest.bytes);
    Map < String, dynamic > parameters = 
      'recvWindow': '5000',
      'timestamp': timeStamp.toString(),
      'signature': signature,
    ;
    Uri uri = Uri.https(baseUrl, path, parameters);
    var response = await http.get(uri, headers: 
      "Accept": "application/json",
      "HTTP_ACCEPT_LANGUAGE": "en-US",
      "Accept-Language": "en-US",
      "X-MBX-APIKEY": "API_KEY_HERE"
    );

    print(response.body);
  

【讨论】:

【参考方案2】:

您的 API 要求签名以十六进制显示 - 因此正则表达式 '^[A-Fa-f0-9]64$' - 即 64 个十六进制大写或小写字符。

使用convert 包将字节转换为十六进制,而不是base64.encode(digest.bytes),它将字节转换为基数64。注意:这不是dart:convert 库。这是一个pub包,所以你必须将它添加到pubspec.yaml并导入它。

那么你可以使用hex.encode(digest.bytes)

【讨论】:

您好,感谢您的回复。我试过hex.encode(digest.bytes),我相信它有效。我仍然遇到code: -1022, msg: Signature for this request is not valid 的问题。但是当我解决这个问题时,我会将您的答案标记为正确答案。因为我相信你的答案是正确的。再次感谢好心的陌生人。 是的,它确实有效。我只需要将String signature = base64.encode(digest.bytes); 更改为String signature = hex.encode(digest.bytes);。但我还必须将List&lt;int&gt; key = base64.decode(secret); 更改为List&lt;int&gt; key = utf8.encode(secret);。再次感谢您的帮助!我会将工作代码添加到我的问题中,并将您的答案标记为正确的。

以上是关于如何使用 Dart 签署 Binance HTTP 请求的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 HTTP 请求(Flutter/Dart)检查 Internet 连接?

如何使用 Dart http 向后端添加数据

dart - 如何使用 http.post 实时获取我的数据?

如何使用 Binance API,通过股票代码简单 GET 价格

如何在 Windows Form C# 中使用 Binance API [关闭]

如何将美元平价的所有硬币获取到 Binance API?