优惠券兑换码生成算法

1.兑换码要求

要求如下:

  • 可读性好:兑换码是要给用户使用的,用户需要输入兑换码,因此可读性必须好。我们的要求:

    • 长度不超过10个字符

    • 只能是24个大写字母和8个数字:ABCDEFGHJKLMNPQRSTUVWXYZ23456789

  • 数据量大:优惠活动比较频繁,必须有充足的兑换码,最好有10亿以上的量

  • 唯一性:10亿兑换码都必须唯一,不能重复,否则会出现兑换混乱的情况

  • 不可重兑:兑换码必须便于校验兑换状态,避免重复兑换

  • 防止爆刷:兑换码的规律性不能很明显,不能轻易被人猜测到其它兑换码

  • 高效:兑换码生成、验证的算法必须保证效率,避免对数据库带来较大的压力

2.Base32转码

把二进制数经过加密得到字符的算法就是Base32法,类似的还有Base64法。

举例:假如我们经过自增id计算出一个复杂数字,转为二进制,并每5位一组,结果如下:

01001 00010 01100 10010 01101 11000 01101 00010 11110 11010

此时,我们看看每一组的结果:

  • 01001转10进制是9,查数组得字符为:K

  • 00010转10进制是2,查数组得字符为:C

  • 01100转10进制是12,查数组得字符为:N

  • 10010转10进制是18,查数组得字符为:B

  • 01101转10进制是13,查数组得字符为:P

  • 11000转10进制是24,查数组得字符为:2

  • ...

依此类推,最终那一串二进制数得到的结果就是KCNBP2PC84,刚好符合我们的需求。

综上,我们可以利用自增id作为兑换码,但是要利用Base32加密,转为我们要求的格式。此时就符合了我们的几个要求了:

  • 可读性好:可以转为要求的字母和数字的格式,长度还不超过10个字符

  • 数据量大:可以应对40亿以上的数据规模

  • 唯一性:自增id,绝对唯一

3.重兑校验算法

  • 基于数据库:我们在设计数据库时有一个字段就是标示兑换码状态,每次兑换时可以到数据库查询状态,避免重兑。

    • 优点:简单

    • 缺点:对数据库压力大

  • 基于BitMap:兑换或没兑换就是两个状态,对应0和1,而兑换码使用的是自增id.我们如果每一个自增id对应一个bit位,用每一个bit位的状态表示兑换状态,是不是完美解决问题。而这种算法恰好就是BitMap的底层实现,而且Redis中的BitMap刚好能支持2^32个bit位。

    • 优点:简答、高效、性能好

    • 缺点:依赖于Redis

4.防刷校验算法

JWT分为三部分组成:

  • Header:记录算法

  • Payload:记录用户信息

  • Verify Signature:验签,用于验证整个token

JWT中的的Header和Payload采用的是Base64算法,与我们Base32类似,几乎算是明文传输,难道不怕其他人伪造、篡改token吗?

为了解决这个问题,JWT中才有了第三部分,验证签名。这个签名是有一个秘钥,结合Header、Payload,利用MD5或者RSA算法生成的。因此:

  • 只要秘钥不泄露,其他人就无法伪造签名,也就无法伪造token。

  • 有人篡改了token,验签时会根据header和payload再次计算签名。数据被篡改,计算的到的签名肯定不一致,就是无效token

因此,我们也可以模拟这种思路:

  • 首先准备一个秘钥

  • 然后利用秘钥对自增id做加密,生成签名

  • 将签名、自增id利用Base32转码后生成兑换码

只要秘钥不泄露,就没有人能伪造兑换码。只要兑换码被篡改,就会导致验签不通过。

当然,这里我们不能采用MD5和RSA算法来生成签名,因为这些算法得到的签名都太长了,一般都是128位以上,超出了长度限制。

因此,这里我们必须采用一种特殊的签名算法。由于我们的兑换码核心是自增id,也就是数字,因此这里我们打算采用按位加权的签名算法:

  • 将自增id(32位)每4位分为一组,共8组,都转为10进制

  • 每一组给不同权重

  • 把每一组数加权求和,得到的结果就是签名

举例:

最终的加权和就是:4*2 + 2*5 + 9*1 + 10*3 + 8*4 + 2*7 + 1*8 + 6*9 = 165

这里的权重数组就可以理解为加密的秘钥

当然,为了避免秘钥被人猜测出规律,我们可以准备16组秘钥。在兑换码自增id前拼接一个4位的新鲜值,可以是随机的。这个值是多少,就取第几组秘钥。

这样就进一步增加了兑换码的复杂度。

最后,把加权和,也就是签名也转二进制,拼接到最前面,最终的兑换码就是这样:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值