移动网页APP保持用户登录的改进方案(UUID Redis Token)

一 面临问题

当前移动app最常见的保持登录的方案就是:持续刷新的JWT(json web token)方案。
即用户登录后,客户端获得JWT,此后不断刷新或是过去后刷新。
这个方案有两个问题:
1,JWT 自身的问题。
JWT 的安全的基石是保证秘钥(secret key)的安全,因为一旦秘钥泄露,拥有秘钥的人可以伪造所有用户。这给管理带来了麻烦,我们还要完全信任管理人员,管理人员变动就要修改秘钥,而修改秘钥又会打断用户的登录状态。也许有人会说,这不是问题,这个和数据库账号密码管理一样啊,这个还有些不同,生产环境的数据库账号密码通常会有登录IP限制。
2,JWT 的刷新机制有问题。
为了安全,很多人都知道token长期保持不变不安全,通常会采取刷新token的机制。当是当下,很多刷新机制是为了刷新而刷新,常见的刷新机制是:token到期后或是提前刷新,或者就是定时刷新。如果token被盗,黑客和合法用户都可以通过刷新来获取新的token,这并没带来实际的安全提升。

二 问题解答

1,针对JWT秘钥管理问题
这里给出的方案就是不使用JWT, 采用一个类似session 的机制,使用一个随机值(uuid)做token, 数据到后台集中的redis存储查询。暂且称之为UUID Redis Token.
JWT的最大有点就是自身和存储用户数据,不用到集中的存储点查询,便于分布式应用,这个特点导致了已发布的JWT不易撤销。现实中,很多使用JWT的公司并不是单纯的在jwt里取用户数据,依旧在服务器取数据。还有,对于像图片,视频等需要用户登录的检查,通常把token放到url 里,而JWT显得数据过大。
使用redis在后端保存用户信息有良好的扩展性,足够应满足大型网站的需求。
讲到这里,这个机制和传统的session 机制是一样的,uuid 相当于session-id.
这个的uuid 并不要求按标准格式,只需不重复即可,对于PHP 很容易生成

$token = bin2hex(random_bytes(20));

2 UUID Redis Token的特点和刷新机制

  • 每个token有一个较长的有效期,比如90天,这个是为了满足长期登录的需求
  • 每个token有一个较短的刷新间隔,比如2个小时。常常更换token 提升安全性
  • 每当token刷新时,创建新的token,同时修改旧的token的有效期,比如60秒后过期,保证旧的token短暂可用,(并发请求时,可能会用到旧token)
  • 每当用户重新登录或是修改密码,删除token。
  • 利用redis或mysql 的锁机制,确保并发请求时只有个刷到新的token。
    服务器token处理逻辑:通过token在redis里获取用户数据,如果找不到则表示token失效或错误,要求用户再次登录。如果找到用户信息且token 是2个小时内创建的,则不刷新token, 如果token创建时间超过2个小时前,则创建新的token给用户,服务器复制用户数据到新的token,同时修改旧token 60秒后过期。