天天看點

第三方接口調用的參數加密驗簽

首先,下面的方式隻支援post請求,get方式可以自己擴充。每當一個不能鑒權的接口需要被其它服務調用時,如果這個接口會暴漏在公網上,那麼這個不能鑒權的接口或者無token的接口就需要換一種方式進行權限驗證。通常使用的方法是參數加密。調用方和被調用方參數使用同一種規則加密,比對成功,則允許請求,比對失敗,則拒絕請求。這種根據參數加密的方式往往能防止請求被其他方攔截後篡改參數,進行非法請求。這種加密有以下幾種作用:

1. 加密時可以附帶接口請求時的時間戳,這樣可以保證一個接口隻能在有效期内被通路。

2. 參數加密時可以加密鑰串一起再加密,確定參數規則被人識别後,也能篡改參數,如果别人也識别出你的加密規則,但是他沒有密鑰串,即使加密後也會請求失敗。

3. 加密後的密碼很難被逆向解密,加密後,即使被攔截,加密串和參數雖然都被非法擷取,但是不能修改任意參數再請求,而且請求也會有時間限制。確定了接口的安全性。

看代碼:

@Slf4j
public class ParamsEncodeUtil {
    public static void main(String[] args) {
        Map<String, Object> map = new HashMap<>();
        map.put("prizeGoodsCode", "prizeGoodsCode");
        map.put("prizeGoodsName", "prizeGoodsName");
        map.put("prizeGoodsNum", 1);
        map.put("userId", 123);
        map.put("userName", "userName");
        map.put("winPrizeTime", new Date());
        map.put("timestamp", System.currentTimeMillis());
        String secret = "z123";
        System.out.println(createSign(map, secret));
    }

    public static String createSign(Map<String, Object> map, String secret) {
        String secretKEY = MD5Util.md5(secret);
        // 排序 true 升序
        Set<String> keySet = sortByValue(map.keySet(), true);
        map(keySet,map);
        // 拼接簽名串
        StringBuffer signStr = new StringBuffer();
        signStr.append(secretKEY);
        for (String str : keySet) {
            signStr.append(str);
            if (map.get(str) != null) {
                signStr.append(map.get(str));
            }
        }
        System.out.println("###signStr222= "+signStr.toString());
        // 加密 md5(base64(signStr)+secretKEY)
        String encode = Base64Utils.base64Encoder(signStr.toString());
        String sign = MD5Util.md5(encode + secretKEY);
        return sign;
    }
    public static void map(Set<String> keySet,Map<String, Object> map){
        Map<String, Object> m = new HashMap<>();
        for (String key : keySet) {
            m.put(key,map.get(key));
        }
        log.info("###keySet= {}", JSON.toJSONString(m));
    }
    public static Set<String> sortByValue(Set<String> set, final Boolean flag) {
        List<String> setList = new ArrayList<String>(set);
        Collections.sort(setList, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                if (flag) {
                    return o1.toString().compareTo(o2.toString());
                } else {
                    return o2.toString().compareTo(o1.toString());
                }

            }

        });
        set = new LinkedHashSet<String>(setList);
        return set;
    }
}

/**
 * MD5工具類
 */
public final class MD5Util {
	public static void main(String[] args) {
		long t1 = System.currentTimeMillis();
		String md5 = md5("20");
		System.out.println(md5);
		long t2 = System.currentTimeMillis();
		System.out.println(t2 - t1);
	}

	protected final static Logger LOG = Logger.getLogger(MD5Util.class.getSimpleName());

	// 用來将位元組轉換成 16 進制表示的字元
	private static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
			'f' };
	private static Charset UTF8 = Charset.forName("UTF-8");

	private MD5Util() {
		throw new RuntimeException("can't init it");
	}

	public static String md5(String from) {
		byte fromByte[] = null;
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
			fromByte = from.getBytes(UTF8);
		} catch (Throwable e) {
			LOG.log(Level.SEVERE, "error while md5 for:" + from, e);
			throw new RuntimeException("error while md5 for:" + from, e);
		}
		byte bs[] = md.digest(fromByte);
		char str[] = new char[16 * 2]; // 每個位元組用 16 進制表示的話,使用兩個字元,
		// 是以表示成 16 進制需要 32 個字元
		int k = 0; // 表示轉換結果中對應的字元位置
		for (int i = 0; i < 16; i++) { // 從第一個位元組開始,對 MD5 的每一個位元組
			// 轉換成 16 進制字元的轉換
			byte byte0 = bs[i]; // 取第 i 個位元組
			str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取位元組中高 4 位的數字轉換,
			// >>> 為邏輯右移,将符号位一起右移
			str[k++] = hexDigits[byte0 & 0xf]; // 取位元組中低 4 位的數字轉換
		}
		return new String(str);
	}
}


/**
 * @Description
 * @Author: jinglonglong
 * @Date:2021-7-16
 **/
public class Base64Utils {
    public static String base64Encoder(String key) {
        BASE64Encoder encoder = new BASE64Encoder();
        String encode = encoder.encode(key.getBytes());
        return encode;
    }

    public static String base64Decoder(String encode) {
        BASE64Decoder decoder = new BASE64Decoder();
        String str = null;
        try {
            byte[] bytes = decoder.decodeBuffer(encode);
            str = new String(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}
           

繼續閱讀