2019-06-17 邀请码的生成(基于自增id与多进制方案)

2019-06-17  本文已影响0人  刘明_d589

项目开发过程中,偶尔会有邀请码需求。
1.生成唯一邀请码
2.得到邀请码的用户可以体验某项业务

这里分享一下邀请码的生成方案。

邀请码的要求: 们先明确邀请码需要的格式

以上要求,同时满足 1、2 两点要求的实现有一定难度。

方案思路

   ——— 涉及程序语言部分以JAVA为例

直接使用JAVA UUID 方式生成。

此方法生成的字符串有36位,去除中间的"-"字符,为32位。可以满足要求1,但无法满足要求2.且长度过长。总的来说,可用,但体验不是特别好。

基于体验码自增ID结合多进制字符串生成

在生成体验码时,我们可以依赖于体验码表的自增id来获得邀请码。基于自增id可以保证不会重复,而且关键数据也是最精简的。

直接使用自增id有两个缺陷:

对于问题一,我们可以使用多进制方案,将数字完美映射到要求的字符集。
对于问题二,我们可以将自增的id与随机数结合起来使用。比如使用6位保存id,取4位保存随机数。将两者结合起来生成邀请码。

对于大小写英文字母加数字的情况,可能出现的字符类型有62种(26*2+10),因此我们可以将id和随机数转化为62进制数,0-9a-zA-Z分别表示0-61的值。这样提供出来的邀请码就是在字符上符合要求,生成的邀请码能够保证唯一。同时,唯一因子只有邀请码id,唯一标准非常精简。如果6位用作自增,4位用作随机。那么我们可以保证全局唯一的邀请码个数有 62^6 = 56800235584 ,总共有568亿个。而一个攻击者如果看出来自增段,想要猜下一个邀请码,则需要从 62^4 = 14776336 ,1千4百万种可能中去猜测。

另外,为了让生成的邀请码看起来不是“某几位字符总是相同的”,可以做一些混合,比如将自增段与随机段混合穿插。亦或使用随机段作为key,将自增段做一次等长加密等。

这里提供转换多进制的工具类:
查看工具类实现原文

public class NumericConvertUtils {

    /**
     * 在进制表示中的字符集合,0-Z分别用于表示最大为62进制的符号表示
     */
    private static final char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

    /**
     * 将十进制的数字转换为指定进制的字符串
     *
     * @param number 十进制的数字
     * @param seed   指定的进制
     * @return 指定进制的字符串
     */
    public static String toOtherNumberSystem(long number, int seed) {
        if (number < 0) {
            number = ((long) 2 * 0x7fffffff) + number + 2;
        }
        char[] buf = new char[32];
        int charPos = 32;
        while ((number / seed) > 0) {
            buf[--charPos] = digits[(int) (number % seed)];
            number /= seed;
        }
        buf[--charPos] = digits[(int) (number % seed)];
        return new String(buf, charPos, (32 - charPos));
    }

    /**
     * 将其它进制的数字(字符串形式)转换为十进制的数字
     *
     * @param number 其它进制的数字(字符串形式)
     * @param seed   指定的进制,也就是参数str的原始进制
     * @return 十进制的数字
     */
    public static long toDecimalNumber(String number, int seed) {
        char[] charBuf = number.toCharArray();
        if (seed == 10) {
            return Long.parseLong(number);
        }

        long result = 0, base = 1;

        for (int i = charBuf.length - 1; i >= 0; i--) {
            int index = 0;
            for (int j = 0, length = digits.length; j < length; j++) {
                //找到对应字符的下标,对应的下标才是具体的数值
                if (digits[j] == charBuf[i]) {
                    index = j;
                }
            }
            result += index * base;
            base *= seed;
        }
        return result;
    }
}

从邀请码的实践中我们可以总结两点:

上一篇 下一篇

猜你喜欢

热点阅读