Skip to content

Latest commit

 

History

History
41 lines (24 loc) · 3.21 KB

File metadata and controls

41 lines (24 loc) · 3.21 KB

用户认证鉴权系统改造梳理(2)

昨天提到的两种方法,各自的优缺点都非常明显,但在目前我们系统这种业务场景下,还是不足够好, 需要一种兼有两者优点的方法,即

  • 接入层鉴权校验时候,不需要每次都与后端网络交互,数据存储IO.
  • 安全性足够高:放篡改,过期机制等

最终方案:单向函数+票据池+定期后端校验

要生成的令牌的内容构成如下:

  • 用户Uid,由于是分布式类snowflake算法生成的,不是自增的,所以不怕被猜到用户数,如果实在敏感 这个字段可以稍微用户RSA加密下。
  • 创建时间createTime,令牌创建后,总有个过期时间,要不然要是被别人截获了请求,就可以一直用这个令牌串,获取用户信息,直到用户发现用户给账户充了钱,才动手。
  • 令牌版本号Version,毕竟万一有一天发现SHA1算法破解率提升了,想换算法到SHA256,线上的用户数据过度要平滑。

最终我们得到 token内容: uid=123456&createTime=150123123&version=1&sign=xxxxxxx 其中sign字段内容是把除sign外的其他字段按照字典排序后,加上一个票据ticket,然后利用单向函数加密生成的字符串。 即 sign=SHA1(一定规则排序后的业务参数+ticket).

那为什么要排序呢,主要是因为对于像MD5,SHA1这样的哈希函数来说,修改一个字母,其得到的结果都会完全不一样,所以为了避免要加密内容出现不应该顺序位置错误,只好每次都按照一定规则排列好来进行加密,这样校验的乙方也按照同样方式进行加密,来比对sign值是否一样,来判断内容是否有被修改。

加密用的ticket如何避免泄露

虽然利用单向函数可以避免每次都去服务端校验,但接入层校验时候,也需要用到授权方生成sign时候的ticket啊,这岂不是和RSA方法遇到问题一样吗?如何避免。

为了避免这个问题,我们只需要启动一个后台线程,这个线程定时的去授权服务中获取ticket票据池,例如一次获取100个,存在本地,然后只需要定一个规则,例如对token中字段创建时间取模,来获得其生成sign时候所选用的ticket. 同时由于ticket数量非常多,也不怕被破解掉一个后造成全部沦陷。而且我们也可以结合version字段,定期更新这个100个ticket.

类似黑名单需要如何解决

由于之前的方式,校验token时候,为了减少和服务端网络io交互,校验规则都在本地进行,但这样一来问题是,只要token不过期,这个用户就算被拉入黑名单了,还是可以继续使用这个token。 那么为了解决这个问题,我们可以采取一种折中方式, 我们长听到这样一句未考证过的话80%的请求发生在20%的时间里

利用这个启发,我们在进行本地校验时候,可以根据token的创建时间,把创建时间距离现在超过1天的,发送到服务端去校验,没超过的就在本地利用授权鉴权服务封装的sdk进行校验就行。 这样一来大部分流量都不会打到鉴权授权服务上,性能得到提高,也解决了问题。