昨天看到大佬们讨论摩拜和 ofo 谁会成,马化腾提到 ofo 使用的是 token 锁。又想起来半年前和同事们讨论过 ofo 这种离线的会变化的锁密码是怎么实现的。那时候也没有细想,不过现在看着 token 锁这个词。。想起来之前写过的这一篇:关于token。原理应该都是一样的。

这里我们假装 geek。用上一篇讲的 token 原理可以很简单地设计出一套 ofo 这样的系统。先来看看 ofo 的系统有哪些组成要件:

车牌号
二维码
服务端返回的 token 值
车锁的密码
app  
其它

车牌号

对人类来说的车辆唯一标识。

二维码

这里面肯定存了车辆的唯一标识,当然了如果你要拿车牌号来当唯一标识也可以。。

服务端返回的 token 值

这个原理和 google authenticator 类似,举个例子,服务器端可以通过类似 google authenticator 的算法,用下面的脚本来生成 token:

import pyotp  
totp = pyotp.TOTP("2SVVV5X3W4DJWBCX")  
print("Current OTP:", totp.now())  

这个算法生成的是 6 位数字,如果我们需要四位,那把前两位扔掉就好。

车锁的密码

我们平常用的 token 一般会选择基于时间的模式,不过也有基于 counter 的模式,这里先假设我们就是基于时间的。在车锁内则需要有一个简单的嵌入式芯片和简单的时钟。特意去淘宝查询了一下,这种时钟模块也就几块人民币。至于这个芯片,因为算法是固定的,我们甚至可以直接把算法焊死在电路上,什么可编程都给我去死吧。这样一个支持时钟的 C 端 token 生成器就完成了。

只要保证时钟问题不大,token 算法和 server 端一致,那两边计算出的 token 就能够始终保持一致。实际上这里的时钟稍微偏差个三五秒的也没关系。又不是手表,不需要那么精准。

app

app 负责扫码,识别出二维码中的车辆唯一标识,去服务器端查询当前车辆的 token 并返回给用户。

另外还需要负责在还车后支付(因为没骑过,我也不清楚是在啥时候支付的)。

另外可能还会负责跟踪车辆轨迹的移动(实际是用户的移动),上报给服务端。

其它

除了上述基本模块,在服务器端是像其它 token 类应用那样存储分发出去的 key 的。例如核心的 id => key 表设计可能下面这样的:

+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id        | bigint(20)  | NO  |     | 0       |       |
| token_key | varchar(30) | NO  |     | ''      |       |
+-----------+-------------+------+-----+---------+-------+

就这么简单~

另外需要考虑的是服务端最重要的 token 查询接口,这个接口的安全性一定要做好。如果 token 锁分发出去的 key 没有办法更改的话,那么如果这个接口的数据被爬,那就相当于可以离线计算出所有车锁的密码。