签名在接口中使用广泛,那么进行接口交互的时候为了保证数据中途不会被篡改需要进行一致性签名,下面将为大家展示个语言一致性前面的算法,同样的内容签名后的数据必须是一致的:
java版本:
1 package cn.com.gome.utils; 2 3 /** 4 * 编码 5 * @author 6 * 7 */ 8 public abstract class Constants { 9 10 /** 11 * TOP默认时间格式 12 */ 13 public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; 14 15 /** 16 * TOP Date默认时区 17 */ 18 public static final String DATE_TIMEZONE = "GMT+8"; 19 20 /** 21 * UTF-8字符集 22 */ 23 public static final String CHARSET_UTF8 = "UTF-8"; 24 25 /** 26 * GBK字符集 27 */ 28 public static final String CHARSET_GBK = "GBK"; 29 30 /** 31 * TOP JSON 应格式 32 */ 33 public static final String FORMAT_JSON = "json"; 34 35 /** 36 * TOP XML 应格式 37 */ 38 public static final String FORMAT_XML = "xml"; 39 40 /** 41 * MD5签名方式 42 */ 43 public static final String SIGN_METHOD_MD5 = "md5"; 44 45 /** 46 * HMAC签名方式 47 */ 48 public static final String SIGN_METHOD_HMAC = "hmac"; 49 50 51 }
1 package cn.com.gome.utils; 2 3 import java.io.IOException; 4 import java.security.GeneralSecurityException; 5 import java.security.MessageDigest; 6 import java.security.NoSuchAlgorithmException; 7 import java.util.Arrays; 8 import java.util.Map; 9 10 import javax.crypto.Mac; 11 import javax.crypto.SecretKey; 12 import javax.crypto.spec.SecretKeySpec; 13 14 import cn.com.gome.utils.StringUtils; 15 16 /** 17 * 签名工具 18 * @author 19 * 20 */ 21 public class SignUtil { 22 /** 23 * 签名算法 24 * 25 * @param params 26 * @param secret 27 * @param signMethod 28 * @return 29 * @throws IOException 30 */ 31 public static String signTopRequest(Map<String, String> params, String secret, String signMethod) 32 throws IOException { 33 // 第一步:检查参数是否已经排序 34 String[] keys = params.keySet().toArray(new String[0]); 35 Arrays.sort(keys); 36 37 // 第二步:把所有参数名和参数值串在一起 38 StringBuilder query = new StringBuilder(); 39 if (Constants.CHARSET_UTF8.equals(signMethod)) { 40 query.append(secret); 41 } 42 for (String key : keys) { 43 String value = params.get(key); 44 if (StringUtils.areNotEmpty(key, value)) { 45 query.append(key).append(value); 46 } 47 } 48 49 // 第三步:使用MD5/HMAC加密 50 byte[] bytes = new byte[0]; 51 if (Constants.CHARSET_UTF8.equals(signMethod)) { 52 bytes = encryptHMAC(query.toString(), secret); 53 } else { 54 query.append(secret); 55 try { 56 bytes = encryptMD5(query.toString()); 57 } catch (NoSuchAlgorithmException e) { 58 // TODO Auto-generated catch block 59 e.printStackTrace(); 60 } 61 } 62 63 // 第四步:把二进制转化为大写的十六进制 64 return byte2hex(bytes); 65 } 66 67 /** 68 * hmac加密 69 * @param data 70 * @param secret 71 * @return 72 * @throws IOException 73 */ 74 public static byte[] encryptHMAC(String data, String secret) throws IOException { 75 byte[] bytes = null; 76 try { 77 SecretKey secretKey = new SecretKeySpec(secret.getBytes(Constants.CHARSET_UTF8), "HmacMD5"); 78 Mac mac = Mac.getInstance(secretKey.getAlgorithm()); 79 mac.init(secretKey); 80 bytes = mac.doFinal(data.getBytes(Constants.CHARSET_UTF8)); 81 } catch (GeneralSecurityException gse) { 82 throw new IOException(gse.toString()); 83 } 84 return bytes; 85 } 86 87 /** 88 * 实现md5加密 89 * @param data 90 * @return 91 * @throws IOException 92 * @throws NoSuchAlgorithmException 93 */ 94 public static byte[] encryptMD5(String data) throws IOException, NoSuchAlgorithmException { 95 96 //确定计算方法 97 MessageDigest md5 = MessageDigest.getInstance("MD5"); 98 return md5.digest(data.getBytes(Constants.CHARSET_UTF8)); 99 } 100 101 /** 102 * 将字节数据进行16位处理 103 * @param bytes 104 * @return 105 */ 106 public static String byte2hex(byte[] bytes) { 107 StringBuilder sign = new StringBuilder(); 108 for (int i = 0; i < bytes.length; i++) { 109 String hex = Integer.toHexString(bytes[i] & 0xFF); 110 if (hex.length() == 1) { 111 sign.append("0"); 112 } 113 sign.append(hex.toUpperCase()); 114 } 115 return sign.toString(); 116 } 117 }
1 package cn.com.gome.utils; 2 3 /** 4 * 字符串工具类 5 * @author 6 * 7 */ 8 public abstract class StringUtils { 9 10 private StringUtils() {} 11 12 /** 13 * 检查指定的字符串是否为空。 14 * <ul> 15 * <li>SysUtils.isEmpty(null) = true</li> 16 * <li>SysUtils.isEmpty("") = true</li> 17 * <li>SysUtils.isEmpty(" ") = true</li> 18 * <li>SysUtils.isEmpty("abc") = false</li> 19 * </ul> 20 * 21 * @param value 待检查的字符串 22 * @return true/false 23 */ 24 public static boolean isEmpty(String value) { 25 int strLen; 26 if (value == null || (strLen = value.length()) == 0) { 27 return true; 28 } 29 for (int i = 0; i < strLen; i++) { 30 if ((Character.isWhitespace(value.charAt(i)) == false)) { 31 return false; 32 } 33 } 34 return true; 35 } 36 37 /** 38 * 检查对象是否为数字型字符串,包含负数开头的。 39 */ 40 public static boolean isNumeric(Object obj) { 41 if (obj == null) { 42 return false; 43 } 44 char[] chars = obj.toString().toCharArray(); 45 int length = chars.length; 46 if(length < 1) 47 return false; 48 49 int i = 0; 50 if(length > 1 && chars[0] == '-') 51 i = 1; 52 53 for (; i < length; i++) { 54 if (!Character.isDigit(chars[i])) { 55 return false; 56 } 57 } 58 return true; 59 } 60 61 /** 62 * 检查指定的字符串列表是否不为空。 63 */ 64 public static boolean areNotEmpty(String... values) { 65 boolean result = true; 66 if (values == null || values.length == 0) { 67 result = false; 68 } else { 69 for (String value : values) { 70 result &= !isEmpty(value); 71 } 72 } 73 return result; 74 } 75 76 /** 77 * 把通用字符编码的字符串转化为汉字编码。 78 */ 79 public static String unicodeToChinese(String unicode) { 80 StringBuilder out = new StringBuilder(); 81 if (!isEmpty(unicode)) { 82 for (int i = 0; i < unicode.length(); i++) { 83 out.append(unicode.charAt(i)); 84 } 85 } 86 return out.toString(); 87 } 88 89 /** 90 * 过滤不可见字符 91 */ 92 public static String stripNonValidXMLCharacters(String input) { 93 if (input == null || ("".equals(input))) 94 return ""; 95 StringBuilder out = new StringBuilder(); 96 char current; 97 for (int i = 0; i < input.length(); i++) { 98 current = input.charAt(i); 99 if ((current == 0x9) || (current == 0xA) || (current == 0xD) 100 || ((current >= 0x20) && (current <= 0xD7FF)) 101 || ((current >= 0xE000) && (current <= 0xFFFD)) 102 || ((current >= 0x10000) && (current <= 0x10FFFF))) 103 out.append(current); 104 } 105 return out.toString(); 106 } 107 108 }
.net版本
1 private static string SignTopRequest(IDictionary<string, string> parameters, string secret, string signMethod) 2 { 3 // 第一步:把字典按Key的字母顺序排序 4 IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal); 5 IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator(); 6 7 // 第二步:把所有参数名和参数值串在一起 8 StringBuilder query = new StringBuilder(); 9 if (Constants.CHARSET_UTF_8.Equals(signMethod)) 10 { 11 query.Append(secret); 12 } 13 while (dem.MoveNext()) 14 { 15 string key = dem.Current.Key; 16 string value = dem.Current.Value; 17 if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)) 18 { 19 query.Append(key).Append(value); 20 } 21 } 22 23 // 第三步:使用MD5/HMAC加密 24 byte[] bytes; 25 if (Constants.CHARSET_UTF_8.Equals(signMethod)) 26 { 27 HMACMD5 hmac = new HMACMD5(Encoding.UTF8.GetBytes(secret)); 28 bytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(query.ToString())); 29 } 30 else 31 { 32 query.Append(secret); 33 MD5 md5 = MD5.Create(); 34 bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(query.ToString())); 35 } 36 37 // 第四步:把二进制转化为大写的十六进制 38 StringBuilder result = new StringBuilder(); 39 for (int i = 0; i < bytes.Length; i++) 40 { 41 result.Append(bytes[i].ToString("X2")); 42 } 43 44 return result.ToString(); 45 }
1 namespace Sys.Common 2 { 3 public sealed class Constants 4 { 5 public static string CHARSET_ISO_2022_JP = "ISO-2022-JP"; 6 public static string CHARSET_ISO_2022_CN = "ISO-2022-CN"; 7 public static string CHARSET_ISO_2022_KR = "ISO-2022-KR"; 8 public static string CHARSET_ISO_8859_5 = "ISO-8859-5"; 9 public static string CHARSET_ISO_8859_7 = "ISO-8859-7"; 10 public static string CHARSET_ISO_8859_8 = "ISO-8859-8"; 11 public static string CHARSET_BIG5 = "BIG5"; 12 public static string CHARSET_GB18030 = "GB18030"; 13 public static string CHARSET_EUC_JP = "EUC-JP"; 14 public static string CHARSET_EUC_KR = "EUC-KR"; 15 public static string CHARSET_EUC_TW = "EUC-TW"; 16 public static string CHARSET_SHIFT_JIS = "SHIFT_JIS"; 17 public static string CHARSET_IBM855 = "IBM855"; 18 public static string CHARSET_IBM866 = "IBM866"; 19 public static string CHARSET_KOI8_R = "KOI8-R"; 20 public static string CHARSET_MACCYRILLIC = "x-mac-cyrillic"; //C#中"MACCYRILLIC"改名了 21 public static string CHARSET_WINDOWS_1251 = "WINDOWS-1251"; 22 public static string CHARSET_WINDOWS_1252 = "WINDOWS-1252"; 23 public static string CHARSET_WINDOWS_1253 = "WINDOWS-1253"; 24 public static string CHARSET_WINDOWS_1255 = "WINDOWS-1255"; 25 public static string CHARSET_UTF_8 = "UTF-8"; 26 public static string CHARSET_UTF_16BE = "UTF-16BE"; 27 public static string CHARSET_UTF_16LE = "UTF-16LE"; 28 public static string CHARSET_UTF_32BE = "UTF-32BE"; 29 public static string CHARSET_UTF_32LE = "UTF-32LE"; 30 public static string CHARSET_TIS_620 = "WINDOWS-874";//C#泰语的TIS-620在.NET里叫WINDOWS-874 31 //.NET直接支持GB2312编码的 32 //public static string CHARSET_HZ_GB_2312 = "GB2312"; 33 34 // WARNING: Listed below are charsets which Java does not support. 35 public static string CHARSET_HZ_GB_2312 = "HZ-GB-2312"; // Simplified Chinese 36 public static string CHARSET_X_ISO_10646_UCS_4_3412 = "X-ISO-10646-UCS-4-3412"; // Malformed UTF-32 37 public static string CHARSET_X_ISO_10646_UCS_4_2143 = "X-ISO-10646-UCS-4-2143"; // Malformed UTF-32 38 } 39 }
golang版本
1 package utils 2 3 import ( 4 "bytes" 5 "crypto/hmac" 6 "crypto/md5" 7 "fmt" 8 "sort" 9 "strconv" 10 "strings" 11 "sync" 12 ) 13 14 //签名的字符编码类型 15 type GOLANG_CHARSET string 16 17 //字符编码类型常量 18 const ( 19 CHARSET_ISO_2022_JP GOLANG_CHARSET = "ISO-2022-JP" 20 CHARSET_ISO_2022_CN = "ISO-2022-CN" 21 CHARSET_ISO_2022_KR = "ISO-2022-KR" 22 CHARSET_ISO_8859_5 = "ISO-8859-5" 23 CHARSET_ISO_8859_7 = "ISO-8859-7" 24 CHARSET_ISO_8859_8 = "ISO-8859-8" 25 CHARSET_BIG5 = "BIG5" 26 CHARSET_GB18030 = "GB18030" 27 CHARSET_EUC_JP = "EUC-JP" 28 CHARSET_EUC_KR = "EUC-KR" 29 CHARSET_EUC_TW = "EUC-TW" 30 CHARSET_SHIFT_JIS = "SHIFT_JIS" 31 CHARSET_IBM855 = "IBM855" 32 CHARSET_IBM866 = "IBM866" 33 CHARSET_KOI8_R = "KOI8-R" 34 CHARSET_MACCYRILLIC = "x-mac-cyrillic" 35 CHARSET_WINDOWS_1251 = "WINDOWS-1251" 36 CHARSET_WINDOWS_1252 = "WINDOWS-1252" 37 CHARSET_WINDOWS_1253 = "WINDOWS-1253" 38 CHARSET_WINDOWS_1255 = "WINDOWS-1255" 39 CHARSET_UTF_8 = "UTF-8" 40 CHARSET_UTF_16BE = "UTF-16BE" 41 CHARSET_UTF_16LE = "UTF-16LE" 42 CHARSET_UTF_32BE = "UTF-32BE" 43 CHARSET_UTF_32LE = "UTF-32LE" 44 CHARSET_TIS_620 = "WINDOWS-874" 45 CHARSET_HZ_GB_2312 = "HZ-GB-2312" 46 CHARSET_X_ISO_10646_UCS_4_3412 = "X-ISO-10646-UCS-4-3412" 47 CHARSET_X_ISO_10646_UCS_4_2143 = "X-ISO-10646-UCS-4-2143" 48 ) 49 50 //当前类的指针 51 var sign *signUtils 52 53 //同步锁 54 var signone sync.Once 55 56 //签名类 57 type signUtils struct { 58 mapExtend *MapExtend 59 } 60 61 //实例化签名 62 func Sign() *signUtils { 63 signone.Do(func() { 64 sign = new(signUtils) 65 sign.mapExtend = new(MapExtend) 66 }) 67 return sign 68 } 69 70 /** 71 签名算法 72 parameters 要签名的数据项 73 secret 生成的publicKey 74 signMethod 签名的字符编码 75 */ 76 func (s *signUtils) SignTopRequest(parameters *map[string]string, secret string, signMethod GOLANG_CHARSET) string { 77 /** 78 1、第一步:把字典按Key的字母顺序排序 79 2、第二步:把所有参数名和参数值串在一起 80 3、第三步:使用MD5/HMAC加密 81 4、第四步:把二进制转化为大写的十六进制 82 */ 83 84 //第一步:把字典按Key的字母顺序排序 85 keys, err := s.mapExtend.GetKeys(parameters) 86 if err != nil { 87 // goto result 88 return "" 89 } 90 sort.Strings(keys) 91 //第二步:把所有参数名和参数值串在一起 92 var bb bytes.Buffer 93 if CHARSET_UTF_8 == signMethod { 94 bb.WriteString(secret) 95 } 96 for i, v := range keys { 97 _ = i 98 val := (*parameters)[v] 99 if len(val) > 0 { 100 bb.WriteString(v) 101 bb.WriteString(val) 102 } 103 } 104 fmt.Println(bb.String()) 105 //第三步:使用MD5/HMAC加密 106 b := make([]byte, 0) 107 if CHARSET_UTF_8 == signMethod { 108 h := hmac.New(md5.New, s.GetUtf8Bytes(secret)) 109 h.Write(bb.Bytes()) 110 b = h.Sum(nil) 111 } else { 112 bb.WriteString(secret) 113 md5instence := md5.New() 114 md5instence.Write(bb.Bytes()) 115 b = md5instence.Sum(nil) 116 } 117 //第四步:把二进制转化为大写的十六进制 118 var result bytes.Buffer 119 for i := 0; i < len(b); i++ { 120 s := strconv.FormatInt(int64(b[i]&0xff), 16) 121 if len(s) == 1 { 122 result.WriteString("0") 123 } 124 result.WriteString(s) 125 } 126 //返回签名完成的字符串 127 return strings.ToUpper(result.String()) 128 } 129 130 //默认utf8字符串 131 func (s *signUtils) GetUtf8Bytes(str string) []byte { 132 b := []byte(str) 133 return b 134 }