接口数据签名说明文档
<h1><strong>简要描述:</strong></h1>
<p>注: <span style="color:red">经常有签名不对的情况!</span>
1、大多数 是因为 ,开发语言的默认排序方式会不一样,导致 参数拼接后的字符串不一样了!
建议 直接把 <span style="color:red">参数名 <strong>都改成小写或者大写</strong></span>,好排序!
【女装网获取参数时不区分大小写,没事的】
2、下面有C#和Java的示例代码:
3、 提供一个签名工具:<a href="http://open.hznzcn.com//sign_test.html">http://open.hznzcn.com//sign_test.html</a> ,可进行签名的测试
<strong>签名加密方式:</strong></p>
<ul>
<li>MD5</li>
<li>utf-8编码</li>
<li>32位</li>
<li>大写</li>
</ul>
<h1><strong>签名规则</strong></h1>
<p><strong><span style="color:red;font-size:25px;">第1步</span>:准备好接口参数,除了接口 需要的 业务参数 外,还包括整个开发平台所有接口都需要的 基础公告参数:app_key(女装网分配的AppKey)、access_token(女装网授权的token)、stamp(stamp为当前时间戳)。 </strong>
注:参数 access_token(女装网开放平台授权成功后的token),如果某个api 是 仅限授权用户使用的,该access_token就一定要参与签名,如果某api可以 匿名可访问 (非仅限授权用户),access_token可以不传参)</p>
<p><strong><span style="color:red;font-size:25px;">第2步</span>:将各个接口参数(stamp、app_key、access_token及其它业务参数),以参数名进行升序排序,排序后,再以 参数名和参数值 的形式,拼接形成一个待签名的 字符串data。</strong></p>
<ul>
<li>优先 数字、其次 小写字母、最后 大写字母 的顺序,进行升序排序</li>
<li>【重点】各个语言的排序可能会有差异,可以将参数名全小写,再升序排序,女装网开放平台对请求参数的名称,大小写不敏感</li>
<li>可以参考C#语言中的 SortedDictionary<string, string> 类型的排序</li>
<li><span style="color:red;font-size:25px;">【重点】拼接字符串时,如果参数的值为null或者为空,请过滤,不要拼接,参与签名</span></li>
</ul>
<p><strong><span style="color:red;font-size:25px;">第3步</span>:把私钥(Secret,女装网提供),拼到第2步拼接好后的 字符串data 最后面</strong></p>
<p><br/>
<br/></p>
<h1><strong>下面是具体示例图和过程</strong></h1>
<ul>
<li>json参数是<a href="https://www.showdoc.cc/230407611622153?page_id=1313862750462126" title=" 获取授权,token"> 获取授权,token</a> 的请求参数,这里用来演示</li>
</ul>
<pre><code>{
"app_key": "1",
"grant_type": "password",
"loginway": "1",
"username": "18888888888",
"password": "PPPPPPPPPPPPPPPP",
"stamp": "637199749398998058"
}
</code></pre>
<p>1、准备参数数据阶段(下图,参数未排序)
<img src="https://www.showdoc.cc/server/api/common/visitfile/sign/907a3c2299385ff1e0257292385b194c?showdoc=.jpg" alt="" /></p>
<p>2、签名前阶段1,(下图,已经对参数进行了排序)
<img src="https://www.showdoc.cc/server/api/common/visitfile/sign/7cb4b1f16e98b47931800c9fb92bdb14?showdoc=.jpg" alt="" /></p>
<p>3、签名前阶段2(排序后,所有参数的key和值进行 拼接)</p>
<pre><code>以 参数名和参数值 的形式,拼接形成一个字符串【如果参数没值,就过滤不参与拼接】;
得到的字符串为:app_key1grant_typepasswordloginway1passwordPPPPPPPPPPPPPPPPstamp637199749398998058username18888888888</code></pre>
<p>4、签名前阶段3(拼接私钥Secret)【生成最终的待签名字符串】</p>
<pre><code>把私钥(Secret:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx),拼到 签名前阶段2 的带的 字符串 最后面,
最后得到:
app_key1grant_typepasswordloginway1passwordPPPPPPPPPPPPPPPPstamp637199749398998058username18888888888xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</code></pre>
<p>5、 进行签名:使用MD5(utf-8编码, 32位 大写)对以上字符串加密</p>
<pre><code>最终得到的签名字符串:A4D0EF594C0996658E552A555E37CCF9</code></pre>
<p>6、提供一个 签名工具:<a href="http://open.hznzcn.com//sign_test.html">http://open.hznzcn.com//sign_test.html</a> ,可进行签名的测试
<img src="https://www.showdoc.cc/server/api/common/visitfile/sign/025b62c9076ad3ebffd2170a7ab560f4?showdoc=.jpg" alt="" /></p>
<h1><strong>签名的参考代码</strong></h1>
<ul>
<li>下面有两个示例代码:C#和Java</li>
</ul>
<h3>C#示例代码:</h3>
<pre><code class="language-csharp">/// <summary>
/// 取得数据签名
/// </summary>
/// <param name="sParaTemp">参数字典</param>.
/// <param name="appSecret">女装网提供的appSecret</param>
/// <returns></returns>
public static string GetSign(SortedDictionary<string , string> sParaTemp, string appSecret)
{
StringBuilder sb = new StringBuilder();
//按keyvaluekeyvalue...拼装
foreach (KeyValuePair <string, string> kv in sParaTemp)
{
//如果参数名和参数值不为空,才拼接
if (!string .IsNullOrEmpty(kv.Key) && !string.IsNullOrEmpty(kv.Value) && kv.Key != "")
{
sb.Append(kv.Key).Append(kv.Value);
}
}
//把密钥追加到参数值末尾
sb.Append(appSecret);
//使用utf-8编码,MD5加密
MD5 md5 = MD5 .Create();
byte[] bytes = md5.ComputeHash(Encoding .UTF8.GetBytes(sb.ToString()));
//把二进制转化为大写的十六进制
StringBuilder result = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
result.Append(bytes[i].ToString( "X2"));
}
return result.ToString();
}
</code></pre>
<h3>Java示例代码:</h3>
<pre><code class="language-java">/**
* 获取签名
*/
public static String getSign(Map<String, String> map,String secret){
String sign= "";
Map<String, String> signMap = paraFilter(map);//过滤空值
String str = createLinkString(signMap)+secret;//把参数拼接成 待签名的字符串
sign = Md5Util.encode(str);//Md5加密,下面提供了 Md5Util类【 Md5Util.java】
return sign;
}
/**
* 参数过虑,空值过虑,并返回过虑后的,参与签名的 Map
*/
public static Map<String, String> paraFilter(Map<String, String> sArray) {
Map<String, String> result = new HashMap<String, String>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
//参数名或者参数值为空,过滤掉
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把参数拼接成 待签名的字符串
*/
public static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);//进行排序;该sort仅适用于keys都是小写或者大写的情况,若存在大小写等复杂情况,可能需要优化排序
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
prestr = prestr + key + value;
}
return prestr;
}
</code></pre>
<h3>Md5Util.java</h3>
<pre><code class="language-java">package com.idorabox.core.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
public final class Md5Util {
public static final String JT_CHARSET = "UTF-8";
private static final char hexDigits[] = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
public static String encode(File file) {
FileInputStream in = null;
MessageDigest md5 = null;
try {
in = new FileInputStream(file);
FileChannel ch = in.getChannel();
MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY,
0, file.length());
md5 = MessageDigest.getInstance("MD5");
md5.update(byteBuffer);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return toHex(md5.digest());
}
public static String encode(String arg) {
if (arg == null) {
arg = "";
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
md5.update(arg.getBytes(JT_CHARSET));
} catch (Exception e) {
e.printStackTrace();
}
return toHex(md5.digest());
}
private static String toHex(byte[] bytes) {
StringBuffer str = new StringBuffer(32);
for (byte b : bytes) {
str.append(hexDigits[(b & 0xf0) >> 4]);
str.append(hexDigits[(b & 0x0f)]);
}
return str.toString();
}
}</code></pre>
<h3>PHP MD5代码</h3>
<pre><code class="language-php">$s1=md5("待加密签名的字符串");
$signs=strtoupper($s1);</code></pre>
<h3>Jquery MD5代码</h3>
<ul>
<li>需要导入md5的js</li>
</ul>
<pre><code class="language-javascript">var sign=$.md5("待加密签名的字符串").toUpperCase();</code></pre>