如何使用 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' + '×tamp=' + 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' + '×tamp=' + 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<int> key = base64.decode(secret);
更改为List<int> key = utf8.encode(secret);
。再次感谢您的帮助!我会将工作代码添加到我的问题中,并将您的答案标记为正确的。以上是关于如何使用 Dart 签署 Binance HTTP 请求的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 HTTP 请求(Flutter/Dart)检查 Internet 连接?
dart - 如何使用 http.post 实时获取我的数据?
如何使用 Binance API,通过股票代码简单 GET 价格