zoukankan      html  css  js  c++  java
  • Java工具类SignUtil


    
    import javax.crypto.Mac;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    import java.io.IOException;
    import java.security.GeneralSecurityException;
    import java.util.Arrays;
    import java.util.Map;
    
    /**
     * 为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,TOP服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝。签名算法有两种:MD5(sign_method=md5),HMAC_MD5(sign_method=hmac),签名大体过程如下:
         对所有API请求参数(包括公共参数和业务参数,但除去sign参数和byte[]类型的参数),根据参数名称的ASCII码表的顺序排序。如:foo:1, bar:2, foo_bar:3, foobar:4排序后的顺序是bar:2, foo:1, foo_bar:3, foobar:4。
         将排序好的参数名和参数值拼装在一起,根据上面的示例得到的结果为:bar2foo1foo_bar3foobar4。
         把拼装好的字符串采用utf-8编码,使用签名算法对编码后的字节流进行摘要。如果使用MD5算法,则需要在拼装的字符串前后加上app的secret后,再进行摘要,如:md5(secret+bar2foo1foo_bar3foobar4+secret);如果使用HMAC_MD5算法,则需要用app的secret初始化摘要算法后,再进行摘要,如:hmac_md5(bar2foo1foo_bar3foobar4)。
         将摘要得到的字节流结果使用十六进制表示,如:hex(“helloworld”.getBytes(“utf-8”)) = “68656C6C6F776F726C64”
         说明:MD5和HMAC_MD5都是128位长度的摘要算法,用16进制表示,一个十六进制的字符能表示4个位,所以签名后的字符串长度固定为32个十六进制字符。
     */
    public class SignUtil {
        public static final String SIGN_METHOD_MD5 = "md5";
        public static final String SIGN_METHOD_HMAC = "hmac";
        public static final String CHARSET_UTF8 = "UTF-8";
    
        public static String signTopRequest(Map<String, String> params, String secret, String signMethod) throws IOException {
            // 第一步:检查参数是否已经排序
            String[] keys = params.keySet().toArray(new String[0]);
            Arrays.sort(keys);
    
            // 第二步:把所有参数名和参数值串在一起
            StringBuilder query = new StringBuilder();
            if (SIGN_METHOD_MD5.equals(signMethod)) {
                query.append(secret);
            }
            for (String key : keys) {
                String value = params.get(key);
                if (StringUtils.areNotEmpty(key, value)) {
                    query.append(key).append(value);
                }
            }
    
            // 第三步:使用MD5/HMAC加密
            byte[] bytes;
            if (SIGN_METHOD_HMAC.equals(signMethod)) {
                bytes = encryptHMAC(query.toString(), secret);
            } else {
                query.append(secret);
                bytes = encryptMD5(query.toString());
            }
    
            // 第四步:把二进制转化为大写的十六进制(正确签名应该为32大写字符串,此方法需要时使用)
            return byte2hex(bytes);
        }
    
        private static byte[] encryptHMAC(String data, String secret) throws IOException {
            byte[] bytes;
            try {
                SecretKey secretKey = new SecretKeySpec(secret.getBytes(CHARSET_UTF8), "HmacMD5");
                Mac mac = Mac.getInstance(secretKey.getAlgorithm());
                mac.init(secretKey);
                bytes = mac.doFinal(data.getBytes(CHARSET_UTF8));
            } catch (GeneralSecurityException gse) {
                throw new IOException(gse.toString());
            }
            return bytes;
        }
    
        private static byte[] encryptMD5(String data) throws IOException {
            return encryptMD5(data.getBytes(CHARSET_UTF8).toString());
        }
    
        private static String byte2hex(byte[] bytes) {
            StringBuilder sign = new StringBuilder();
            for (byte aByte : bytes) {
                String hex = Integer.toHexString(aByte & 0xFF);
                if (hex.length() == 1) {
                    sign.append("0");
                }
                sign.append(hex.toUpperCase());
            }
            return sign.toString();
        }
    }
    
  • 相关阅读:
    HQ-day8 函数
    HQ-day7 随机数案例:随机出验证码,对照输入,判断是否正确
    HQ-day6 C#类
    获取用户IP 查找所在城市
    MVC 日常所用
    SQLServer·面试题
    关于WCF开发 相应流程注意事项
    存储过程更新
    存储过程删除举例
    存储过程添加举例
  • 原文地址:https://www.cnblogs.com/dafengdeai/p/12506751.html
Copyright © 2011-2022 走看看