【C#实战】招商银行接口对接全流程揭秘:从鉴权SM2withSM3签名到数据交互一气呵成!
·
【C#实战】招商银行接口对接全流程揭秘:从鉴权SM2withSM3签名到数据交互一气呵成!
本文将完整展示如何使用C#实现招商银行接口的调用全流程,涵盖SM2签名生成、请求头鉴权参数设置、以及数据的上传与获取,为正在对接招行接口的开发者提供一份实用的参考指南。
招商银行接口参数详情
1. 请求头参数说明
| 参数名 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| appid | string | 是 | 应用唯一标识,在招商银行开放平台创建应用后获得 |
| timestamp | string | 是 | 10位Unix时间戳,接口请求时间 |
| sign | string | 是 | 请求签名,示例中使用固定值"123",实际需按规则生成 |
| apisign | string | 是 | 基于SM2算法的签名值 |
| verify | string | 是 | 签名算法类型,固定为"SM3withSM2" |
2. 签名参数说明
签名内容格式:appid={appid}&secret={secret}&sign={sign}×tamp={timestamp}
| 参数名 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| appid | string | 是 | 应用唯一标识 |
| secret | string | 是 | 应用密钥,与appid对应 |
| sign | string | 是 | 请求签名值 |
| timestamp | string | 是 | 10位Unix时间戳 |
3. 业务接口参数示例
数据查询接口(GET)
https://url?merchantId=
| 参数名 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
| merchantId | string | 是 | 商户编号 |
整体流程概览
招行接口调用主要分为以下几个关键步骤:
-
初始化国密曲线参数
-
生成10位时间戳
-
构造签名内容并生成SM2withSM3签名
-
设置HTTP请求头包括appid、timestamp、sign、apisign和verify
-
执行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×tamp=" + 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;
}
}
关键要点总结
-
签名生成:使用SM2withSM3算法生成签名,注意签名内容的构造格式
-
请求头设置:必须包含appid、timestamp、sign、apisign和verify五个头部信息
-
时间戳格式:使用10位Unix时间戳
-
异常处理:建议在生产环境中添加完善的异常处理和日志记录
通过以上完整流程,开发者可以快速实现与招商银行接口的对接工作,确保数据交互的安全性和可靠性。
更多推荐
所有评论(0)