C# API 签名验证 接口文档

ralpo | | 访问(56)

  公共参数

  调用任何一个API都必须传入的参数,目前支持的公共参数有:

  参数名类型说明

  expires:时间戳 (1970-1-1 00:00:00 至 当前时间 的总秒数), 将时间格式转换为Unix时间戳格式 ,取整保留13位,服务端允许客户端请求最大时间误差为3分钟。

  sign:API输入参数签名结果,签名算法参照下面的介绍。

  注意事项

  所有的请求和响应数据编码皆为utf-8格式,所有API都已POST请求方式,无需做URL编码。

  签名算法:

  为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝。目前支持的签名算法为:MD5(sign_method=md5),签名大体过程如下:

  对所有API请求参数(包括公共参数和业务参数,但除去sign参数),根据参数名称的ASCII码表的顺序排序。

  如:param=orderStatus=2&pageIndex=1&pageSize=10&expires=1545705542890 

  排序后的顺序是param=&&&00011122445555789====ISSaaaddeeeeeeeggiinoppprrrssttuxxz 

  不管是get方式和post方式请求,参数都需要 & 拼接 然后排序。

  拼接账号密码,账号UserName+密码Password+排序后的参数字符串,需要转 小写,

  把拼装好的字符串转换成小写字符串采用utf-8编码,使用MD5算法,如:md5(UserName+Password+param),签名后的字符串长度固定为32个十六进制字符。

  签名算法 举例:

  1、原始地址:

  https://notes.clump.cc/search?orderStatus=2&pageIndex=1&pageSize=10&expires=1545705542890

  2、将参数 按ASCII码表的顺序排序

  param=orderStatus=2&pageIndex=1&pageSize=10&expires=1545705542890

  排序后:

  param=&&&00011122445555789====ISSaaaddeeeeeeeggiinoppprrrssttuxxz

  注意: 所有接口 都必须 传 expires=时间戳, 生成签名后的 url 在指定时间内会过期!

  3、获取签名 key 我们会提供 账号UserName,密码Password 私信方式提供

  测试环境:UserName=wms_data_002

  测试环境:Password=ds#!&H3_T#y#00294$-500$0w1mH21#@

  key=UserName+Password+param:

  拼接后结果:key=wms_data_002ds#!&H3_T#y#00294$-500$0w1mH21#@&&&00011122445555789====ISSaaaddeeeeeeeggiinoppprrrssttuxxz

  key 需要转 小写

  key=wms_data_002ds#!&h3_t#y#00294$-5*00$0w1mh21#@&&&00011122445555789====issaaaddeeeeeeeggiinoppprrrssttuxxz

  4、md5 加密 utf8 编码

  将 转小写 key md5 加密 即可得出 sign

  sign:39de8b9482ccb4926386f81fa29c2897

  签名后的地址:https://notes.clump.cc/search?orderStatus=2&pageIndex=1&pageSize=10&expires=1545705542890&sign=39de8b9482ccb4926386f81fa29c2897

  C# 签名代码示例:

/// <summary>
/// 将地址转换成 签名后的地址
/// </summary>
public string GetSign(string param, string userName, string passWord)
{
    param += (!string.IsNullOrWhiteSpace(param) ? "&expires=" : "expires=") + ToTimestamp();
    char[] arrayParam = param.ToArray();
    Array.Sort(arrayParam);//对字符串进行排序
    string newParam = new string(arrayParam);
    string key = string.Format("{0}{1}{2}", userName, passWord, newParam).ToLower();
    return ToMD5(key);
}

/// <summary>  
/// 将Datetime转换成时间戳(1970-1-1 00:00:00 至 当前时间 的总秒数), 将DateTime时间格式转换为Unix时间戳格式 ,取整为保留13位
/// </summary>    
public long ToTimestamp()
{
    DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1, 0, 0, 0, 0));
    return (DateTime.Now.Ticks - startTime.Ticks) / 10000;// 除10000调整为13位
}

/// <summary>
/// md5加密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string ToMD5(string str)
{
    StringBuilder builder = new StringBuilder(0x20);
    byte[] buffer = new MD5CryptoServiceProvider().ComputeHash(Encoding.GetEncoding("utf-8").GetBytes(str));
    for (int i = 0; i < buffer.Length; i++)
    {
        builder.Append(buffer[i].ToString("x").PadLeft(2, '0'));
    }
    return builder.ToString();
}

  Java 签名代码示例:

/**
 * 获取签名
 */
public static String GetSign(String param, String userName, String passWord)
{
    try
    {
        // param += "expires=时间戳"; // 自行添加
        String buildParam = param;
        char[] arrayParam = param.toCharArray();
        Arrays.sort(arrayParam);// 对字符串进行排序
        buildParam = new String(arrayParam);
        return getMD5((userName + passWord + buildParam).toLowerCase());
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}

/**
 * 字符串MD5加密
 */
public static String getMD5(String str)
{
    MessageDigest messageDigest = null;
    try
    {
        messageDigest = MessageDigest.getInstance("MD5");
        messageDigest.reset();
        messageDigest.update(str.getBytes("UTF-8"));
    }
    catch (NoSuchAlgorithmException e)
    {
        System.exit(-1);
    }
    catch (UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }
    byte[] byteArray = messageDigest.digest();
    StringBuffer md5StrBuff = new StringBuffer();
    for (int i = 0; i < byteArray.length; i++)
    {
        if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
            md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
        else
            md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
    }
    // 32位加密,从第9位到25位
    return md5StrBuff.toString().toLowerCase();
}