菠萝派商城签名规则是采用菠萝派商城开发规范的平台统一使用的签名规则。目的为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝。目前支持的签名算法只支持MD5,签名大体过程如下:
将除Sign参数外的所有“参数 参数值”进行字典排序生成串,而后将AppSecret加到该串的首尾,将得到的字符串转小写,进行MD5加密,此时的生成的串即为Sign。以抓单为例,若参数分别为以下值:
appkey=438b2f6ff103422a98a9349507293bb2
bizcontent={"OrderStatus":"JH_01","PlatOrderNo":"20182270207","StartTime":"2016-07-26 10:59:10","EndTime":"2016-08-02 10:59:10","TimeType":"JH_02","PageIndex":"1","PageSize":"20"}
method=Differ.JH.Business.GetOrder
token=9415c33b04d24c7dae320b0185f42fb0
按字典排序生成的串为:appkey438b2f6ff103422a98a9349507293bb2bizcontent{"OrderStatus":"JH_01","PlatOrderNo":"20182270207","StartTime":"2016-07-26 10:59:10","EndTime":"2016-08-02 10:59:10","TimeType":"JH_02","PageIndex":"1","PageSize":"20"}methodDiffer.JH.Business.GetOrdertoken9415c33b04d24c7dae320b0185f42fb0。
若Appsecret=5ee2084de90043be989d4d99d0dd0eaa,则带签名字符串为:
5ee2084de90043be989d4d99d0dd0eaaappkey438b2f6ff103422a98a9349507293bb2bizcontent{"OrderStatus":"JH_01","PlatOrderNo":"20182270207","StartTime":"2016-07-26 10:59:10","EndTime":"2016-08-02 10:59:10","TimeType":"JH_02","PageIndex":"1","PageSize":"20"}methodDiffer.JH.Business.GetOrdertoken9415c33b04d24c7dae320b0185f42fb05ee2084de90043be989d4d99d0dd0eaa
转小写:
5ee2084de90043be989d4d99d0dd0eaaappkey438b2f6ff103422a98a9349507293bb2bizcontent{"orderstatus":"jh_01","platorderno":"20182270207","starttime":"2016-07-26 10:59:10","endtime":"2016-08-02 10:59:10","timetype":"jh_02","pageindex":"1","pagesize":"20"}methoddiffer.jh.business.getordertoken9415c33b04d24c7dae320b0185f42fb05ee2084de90043be989d4d99d0dd0eaa
MD5加密后得到签名:
347e07a557e2720256e64e1e828eff1b (注意,签名也是小写的)
C#签名示例代码
//获得http请求传参
var context = System.Web.HttpContext.Current;
var appkey = context.Request["appkey"];
var token = context.Request["token"];
var method = context.Request["method"];
var bizcontent= context.Request["bizcontent"];
var sign=context.Request["sign"];
var appSecret = "5ee2084de90043be989d4d99d0dd0eaa"; //appSecret的值通过在菠萝派中申请应用获得
//将参数加入排序字典。
var dic = new SortedDictionary<string, string>();
dic.Add("method", method);
dic.Add("appkey", appkey);
dic.Add("token", token);
dic.Add("bizcontent", bizcontent);
var newSign=Sign(dic,appSecret);
if(sign!=newSign)
{
Response.Write("{\"code\":\"40000\",\"message\":\"Logical Error\",\"subcode\":\"GSE.VERIFYSIGN_FAILURE\",\"submessage\":\"签名验证失败\"}");
}
/// <summary>
/// 生成签名。
/// </summary>
/// <returns></returns>
private string Sign(SortedDictionary<string, string> dic,string appSecret)
{
//构建待签名的字符串。
var beSignText = string.Empty;
foreach (string _key in dic.Keys)
beSignText += _key + dic[_key];
//转小写生成签名。
return this.MD5((appSecret + beSignText + appSecret).ToLower());
}
/// <summary>
/// 字符串生成MD5码。
/// </summary>
/// <param name="data">待MD5字符</param>
/// <returns></returns>
public string MD5(string data)
{
var bytes = Encoding.UTF8.GetBytes(data);
var hashmd5 = new MD5CryptoServiceProvider();
byte[] byteOriginal = hashmd5.ComputeHash(bytes);
StringBuilder ciphertext = new StringBuilder(32);
for (int i = 0; i < byteOriginal.Length; i++)
{
ciphertext.Append(byteOriginal[i].ToString("x").PadLeft(2, '0'));
}
return ciphertext.ToString();
}PHP签名示例代码
//获得http请求传参
$method = $_REQUEST['method'];
$appkey = $_REQUEST['appkey'];
$token = $_REQUEST['token'];
$bizcontent = $_REQUEST['bizcontent'];
$sign = $_REQUEST['sign'];
$appSecret="5ee2084de90043be989d4d99d0dd0eaa"; //appSecret的值通过在菠萝派中申请应用获得
$unsign=$appSecret."appkey".$appkey."bizcontent".$bizcontent."method".$method."token".$token.$appSecret;
$newsign=md5(strtolower($unsign));
if($sign!=$newsign)
{
echo("{\"code\":\"40000\",\"message\":\"Logical Error\",\"subcode\":\"GSE.VERIFYSIGN_FAILURE\",\"submessage\":\"签名验证失败\"}");
}C++签名示例代码
String MD5UTF8String(String ASrc)
{
String strRet = "";
TIdHashMessageDigest5 *MD5Encode = new TIdHashMessageDigest5();
try
{
strRet = MD5Encode->HashStringAsHex(ASrc, Sysutils::TEncoding::UTF8 ).LowerCase();
}
__finally
{
delete MD5Encode;
}
return strRet;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdHTTPServerCommandGet(TIdContext *AContext, TIdHTTPRequestInfo *ARequestInfo,
TIdHTTPResponseInfo *AResponseInfo)
{
String Method = ARequestInfo->Params->Values["method"];
String Appkey = ARequestInfo->Params->Values["appkey"];
String Token = ARequestInfo->Params->Values["token"];
String Bizcontent = ARequestInfo->Params->Values["bizcontent"];
String Sign = ARequestInfo->Params->Values["sign"];
String AppSecret="5ee2084de90043be989d4d99d0dd0eaa"; //appSecret的值通过在菠萝派中申请应用获得
String Unsign = AppSecret + "appkey" + Appkey
+ "bizcontent" + Bizcontent + "method" + Method + "token" + Token + AppSecret ;
String Newsign = MD5UTF8String(Unsign.LowerCase()).LowerCase();
if (Sign != Newsign)
{
AResponseInfo->ContentText = "{\"code\":\"40000\",\"message\":\"Logical Error\",\"subcode\":\"GSE.VERIFYSIGN_FAILURE\",\"submessage\":\"签名验证失败\"}";
}
}java 签名示例代码
private String GetSign(OriginalRequestInfo request,String appSecret) throws Exception{
SortedMap<String, String> sortedMap = new TreeMap<>();
sortedMap.put("method", request.getMethod());
sortedMap.put("appkey", request.getAppKey());
sortedMap.put("token", request.getToken());
sortedMap.put("bizcontent", request.getBizContent());
StringBuilder sb = new StringBuilder(appSecret);
sortedMap.forEach((name, value) -> {
if(StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)){
sb.append(name).append(value);
}
});
sb.append(appSecret);
return makeMD5(sb.toString().toLowerCase(),EncodingEnum.UTF_8.toString()).toLowerCase();
}
public String makeMD5(String text, String encoding) throws Exception {
if (encoding == null || encoding.isEmpty()) {
encoding = "UTF-8";
}
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] resultByte = text.getBytes(encoding);
byte[] md5Bytes = md5.digest(resultByte);
StringBuilder hexValue = new StringBuilder();
for (byte md5Byte : md5Bytes) {
int val = (md5Byte) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}注意事项:
所有的请求和响应数据编码皆为utf-8格式,URL里的所有参数名和参数值请做URL编码。
所有API请尽量使用POST发起请求。