Hashids的原理及简略实现
Hashids是一个将数字转化为长度较短、唯一且不连续的值的库。特点是:
- 对非负整数都可以生成唯一短id;
- 可以设置不同的盐,具有保密性;
- 递增的输入产生的输出无法预测;
- 代码较短,且不依赖于第三方库。
那么Hashids的原理是什么?Hashids的机制类似于十进制数字转换为16进制的映射,但是做了一点改动:
- 没有使用16进制,而是62进制(26个字母大小写+10个数字);
- 这个「62进制」的映射通过加盐而做了扰动。
首先我们可以实现第一步:
1 | public class Hashids { |
仅有映射显然不足以提供安全性,因此还需要加以扰动。对映射表洗牌可以改变输出值,那么我们如何能够可重放的洗牌,使得每次产生相同的结果呢?Hashids使用了Fisher–Yates洗牌算法的变种。
1 | // Fisher–Yates洗牌算法 |
Hashids使用Fisher–Yates洗牌算法基本思路:每次选择一个数字交换到剩下的数字的最后一位。但每次选择数字是通过盐来选择的,将原算法改进为:
1 | private static String consistentShuffle(String alphabet, String salt) { |
输出结果
1 | salt=sheep -> alphabet=K1RNlAYFWTeX8DEL720Iia9bcfjnBPm4sSCopgUuqz6rQH5xhtOv3ZMGJwdkyV |
Hashids也可以将多个数字生成为1个id,方法是从映射表中选取一些字符作为分隔符。这些分隔符不用于编码,只用于分隔其它编码后的字符。
1 | private static String seps = "cfhistuCFHISTU"; |
输出结果:
1 | 1 -> R |
参考资料: