签名在接口中使用广泛,那么进行接口交互的时候为了保证数据中途不会被篡改需要进行一致性签名,下面将为大家展示个语言一致性前面的算法,同样的内容签名后的数据必须是一致的:
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 }