You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用OpenAPI规范认证Bitstamp HTTP API v2?遇403无效签名错误

问题:Bitstamp API客户端认证失败(403 Invalid signature)

使用Bitstamp的OpenAPI规范通过NSWAG生成客户端后,始终无法完成认证,持续收到403错误:

响应的HTTP状态码不符合预期(403)。
状态码:403
响应内容:
{"status": "error", "reason": "Invalid signature", "code": "API0005"}

自定义的BitstampClient代码如下:

public partial class BitstampClient
{
    private readonly string key;
    private readonly string secret;
    private readonly bool isPublicApi;
    
    public BitstampClient(string key, string secret, IHttpClientFactory httpFactory) : this(httpFactory.CreateClient($"BitstampClient-{key}"))
    {
        this.key = key;
        this.secret = secret;
        this.isPublicApi = false;
    }
    
    public BitstampClient(IHttpClientFactory httpFactory) : this(httpFactory.CreateClient($"BitstampClient-Public"))
    {
        this.isPublicApi = true;
    }
    
    public BitstampClient(string key, string secret) : this(new HttpClient())
    {
        this.key = key;
        this.secret = secret;
    }
    
    partial void PrepareRequest(HttpClient client, HttpRequestMessage request, StringBuilder urlBuilder)
    {
        if (!this.isPublicApi)
        {
            var xauth = $"{"BITSTAMP"} {this.key}";
            var nonce = Guid.NewGuid().ToString();  //DateTime.Now.Ticks;
            var time = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
            var version = "v2";
            var contentType = "application/x-www-form-urlencoded";
            var signature = GetXAuthSignature(nonce, this.key, this.secret, "QWERTY");

            request.Headers.Add("X-Auth", xauth);
            request.Headers.Add("X-Auth-Signature", signature);
            request.Headers.Add("X-Auth-Nonce", nonce.ToString());
            request.Headers.Add("X-Auth-Timestamp", time.ToString());
            request.Headers.Add("X-Auth-Version", version);

            request.Content.Headers.ContentType = null;
        }
    }

    private string GetXAuthSignature(string nonce, string key, string secret, string clientId)
    {
        var msg = $"{nonce}{clientId}{key}";
        return ByteArrayToString(SignHMACSHA256(secret, StringToByteArray(msg))).ToUpper();
    }
    
    private static byte[] SignHMACSHA256(string key, byte[] data)
    {
        var hashMaker = new HMACSHA256(Encoding.ASCII.GetBytes(key));
        return hashMaker.ComputeHash(data);
    }

    private static byte[] StringToByteArray(string str)
    {
        return Encoding.ASCII.GetBytes(str);
    }
    
    private static string ByteArrayToString(byte[] hash)
    {
        return BitConverter.ToString(hash).Replace("-", "").ToLower();
    }
}

问题分析与修复

核心问题1:Nonce格式不符合要求

Bitstamp要求X-Auth-Nonce必须是严格递增的数字值(通常用自增整数或毫秒级时间戳),你当前用Guid.NewGuid().ToString()生成的字符串完全不符合规则,直接导致签名验证失败。

核心问题2:ClientId硬编码错误

GetXAuthSignature里的clientId被硬编码为"QWERTY",但这个值必须是Bitstamp账户API密钥对应的数字用户ID,可在账户的API设置页面查询到。

核心问题3:签名转换逻辑冗余

你先将签名转为小写再转大写,虽然不影响结果,但增加了不必要的转换步骤,可能引入潜在错误。

修复后的代码调整

  1. 替换Nonce生成逻辑,用静态自增计数器确保每次请求的Nonce严格递增
  2. 替换硬编码的ClientId为实际的数字用户ID
  3. 简化签名转换流程
  4. 修正请求Content-Type的设置逻辑

修复后的关键代码片段:

// 维护静态自增计数器,确保Nonce严格递增
private static long _nonceCounter = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

partial void PrepareRequest(HttpClient client, HttpRequestMessage request, StringBuilder urlBuilder)
{
    if (!this.isPublicApi)
    {
        var apiKey = this.key;
        var apiSecret = this.secret;
        var clientId = "你的Bitstamp数字用户ID"; // 替换为实际值
        
        var nonce = Interlocked.Increment(ref _nonceCounter).ToString();
        var timestamp = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
        var version = "v2";
        
        var signature = GetXAuthSignature(nonce, apiKey, apiSecret, clientId);

        request.Headers.Add("X-Auth", $"BITSTAMP {apiKey}");
        request.Headers.Add("X-Auth-Signature", signature);
        request.Headers.Add("X-Auth-Nonce", nonce);
        request.Headers.Add("X-Auth-Timestamp", timestamp.ToString());
        request.Headers.Add("X-Auth-Version", version);

        // 确保请求内容的Content-Type正确
        if (request.Content != null)
        {
            request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
        }
    }
}

private string GetXAuthSignature(string nonce, string key, string secret, string clientId)
{
    var msg = $"{nonce}{clientId}{key}";
    var secretBytes = Encoding.ASCII.GetBytes(secret);
    var msgBytes = Encoding.ASCII.GetBytes(msg);
    
    using var hmac = new HMACSHA256(secretBytes);
    var hashBytes = hmac.ComputeHash(msgBytes);
    
    // 直接生成大写十六进制签名
    return BitConverter.ToString(hashBytes).Replace("-", "").ToUpper();
}

额外注意事项

  • 确保API密钥已开启对应操作的权限(如查询余额、交易等)
  • 本地系统时间需与UTC时间同步,偏差过大将导致X-Auth-Timestamp验证失败
  • 禁止重复使用Nonce,必须保证每次请求的Nonce值严格大于上一次

内容的提问来源于stack exchange,提问作者R4nc1d

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:12:01