【C#实战】招商银行接口对接全流程揭秘:从鉴权SM2withSM3签名到数据交互一气呵成!

本文将完整展示如何使用C#实现招商银行接口的调用全流程,涵盖SM2签名生成、请求头鉴权参数设置、以及数据的上传与获取,为正在对接招行接口的开发者提供一份实用的参考指南。

招商银行接口参数详情

1. 请求头参数说明

参数名类型是否必填描述
appidstring应用唯一标识,在招商银行开放平台创建应用后获得
timestampstring10位Unix时间戳,接口请求时间
signstring请求签名,示例中使用固定值"123",实际需按规则生成
apisignstring基于SM2算法的签名值
verifystring签名算法类型,固定为"SM3withSM2"

2. 签名参数说明

签名内容格式:appid={appid}&secret={secret}&sign={sign}&timestamp={timestamp}

参数名类型是否必填描述
appidstring应用唯一标识
secretstring应用密钥,与appid对应
signstring请求签名值
timestampstring10位Unix时间戳

3. 业务接口参数示例

数据查询接口(GET)
https://url?merchantId=
参数名类型是否必填描述
merchantIdstring商户编号

整体流程概览

招行接口调用主要分为以下几个关键步骤:

  1. 初始化国密曲线参数

  2. 生成10位时间戳

  3. 构造签名内容并生成SM2withSM3签名

  4. 设置HTTP请求头包括appid、timestamp、sign、apisign和verify

  5. 执行GET/POST请求进行数据交互

代码实现详解

1. 初始化椭圆曲线参数

private static X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");
private static ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);

2. 构建鉴权请求核心方法

public static HttpClient MakeRequest()
{
    // 生成10位时间戳
    int timestamp = (int)getTime10();
    
    // 构造待签名内容
    string signContent = "appid=5c9c61f1-6643-4c96-beae-7eab3e941061&secret=2c7f5a1e-a5b7-4a1b-8d35-bcd8b4b2881d&sign=123&timestamp=" + timestamp;
    
    var client = new HttpClient();
    
    // 设置必需请求头
    client.DefaultRequestHeaders.Add("appid", "5c9c61f1-6643-4c96-beae-7eab3e941061");
    client.DefaultRequestHeaders.Add("timestamp", timestamp.ToString());
    client.DefaultRequestHeaders.Add("sign", "123");
    client.DefaultRequestHeaders.Add("apisign", SingOrderGenerateSmSign(signContent));
    client.DefaultRequestHeaders.Add("verify", "SM3withSM2");
    
    return client;
}

3. 时间戳生成工具方法

public static long getTime10()
{
    TimeSpan ts = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1);
    return (long)ts.TotalSeconds;
}

4. SM2签名生成核心逻辑

public static string SingOrderGenerateSmSign(string str)
{
    string privateKey = "";
    AsymmetricKeyParameter SMprivateKey = GetPrivatekeyFromD(new BigInteger(privateKey, 16));
    
    byte[] msg = System.Text.Encoding.UTF8.GetBytes(str);
    var sm2 = new SM2Signer(new SM3Digest());
    ICipherParameters cp = new ParametersWithRandom(SMprivateKey);
    
    sm2.Init(true, cp);
    sm2.BlockUpdate(msg, 0, msg.Length);
    var signbyte = sm2.GenerateSignature();
    
    return Hex.ToHexString(RsAsn1ToPlainByteArray(signbyte));
}

5. 签名格式转换处理

private const int RS_LEN = 32;

private static byte[] RsAsn1ToPlainByteArray(byte[] rsDer)
{
    Asn1Sequence seq = Asn1Sequence.GetInstance(rsDer);
    byte[] r = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[0]).Value);
    byte[] s = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[1]).Value);
    
    byte[] result = new byte[RS_LEN * 2];
    Buffer.BlockCopy(r, 0, result, 0, r.Length);
    Buffer.BlockCopy(s, 0, result, RS_LEN, s.Length);
    
    return result;
}

private static byte[] BigIntToFixexLengthBytes(BigInteger rOrS)
{
    byte[] rs = rOrS.ToByteArray();
    if (rs.Length == RS_LEN) return rs;
    else if (rs.Length == RS_LEN + 1 && rs[0] == 0) 
        return Arrays.CopyOfRange(rs, 1, RS_LEN + 1);
    else if (rs.Length < RS_LEN)
    {
        byte[] result = new byte[RS_LEN];
        Arrays.Fill(result, (byte)0);
        Buffer.BlockCopy(rs, 0, result, RS_LEN - rs.Length, rs.Length);
        return result;
    }
    else
    {
        throw new ArgumentException("err rs: " + Hex.ToHexString(rs));
    }
}

public static ECPrivateKeyParameters GetPrivatekeyFromD(BigInteger d)
{
    return new ECPrivateKeyParameters(d, ecDomainParameters);
}

6. 数据获取接口(GET请求)

public static bool GetHttpData()
{
    try
    {
        var queryString = HttpUtility.ParseQueryString(string.Empty);
        queryString["merchantId"] = "";
        
        var uri = "" + queryString;
        string result = MakeRequest().GetAsync(uri).Result.Content.ReadAsStringAsync().Result;
        
        return true;
    }
    catch (Exception ex)
    {
        // 异常处理逻辑
        return false;
    }
}

7. 数据上传接口(POST请求)

public static bool PostHttpData(string data)
{
    try
    {
        var uri = "";
        
        var content = new StringContent(data);
        content.Headers.ContentType.MediaType = "application/json";
        
        var response = MakeRequest().PostAsync(uri, content).Result;
        var resultContent = response.Content.ReadAsStringAsync().Result;
        var res = JsonConvert.DeserializeObject<ResultMessage<string>>(resultContent);
        
        return true;
    }
    catch (Exception ex)
    {
        // 异常处理逻辑
        return false;
    }
}

关键要点总结

  1. 签名生成:使用SM2withSM3算法生成签名,注意签名内容的构造格式

  2. 请求头设置:必须包含appid、timestamp、sign、apisign和verify五个头部信息

  3. 时间戳格式:使用10位Unix时间戳

  4. 异常处理:建议在生产环境中添加完善的异常处理和日志记录

通过以上完整流程,开发者可以快速实现与招商银行接口的对接工作,确保数据交互的安全性和可靠性。

更多推荐