一文理解OAuth

假设我们的系统登录需要用客户信息授权, 我们需要知道某个 email 是否是客户的员工。

客户提供一个员工表的账号,通过这个账号,我们可以读到如下数据表

... email phone password ...
pony@tct.inc 1882375662 4b3e3c2f99046f9
ntmgr@tct.inc 1726639880 d0cd2693b35066
pk1_sgmgr@tct.inc 1783305223 e55f86a1f9e06e5

客户将这个账号设为只读账号,防止我们不小心修改员工表信息。

通过上表,我们可以将用户 email 和上表 email 进行比对,实现验证。

用户使用我们的系统时,在我们的登录页输入框中输入自己的 email,我们拿到用户 email 后将用户提供的 email 和客户数据库中的 email 对比,验证成功后进入系统。

系统平稳运行三个月。

客户表示,这种方式我们可以遍历员工表,可以获知他们公司的员工组成。

于是我们联系客户,改成了第二种方式。

客户提供一个方法

(email) => boolean
复制代码

这个方法暴露为接口,我们调用这个接口验证用户的 email 是否正确。这种方法我们无法读取到客户公司所有的 email。

但我们可以用编造出来的很多 email 请求这个接口,通过返回的是否是本公司员工猜出客户公司的员工组成。考虑到这一点,客户设计接口时增加了接口调用限制,一天 200 次请求,这样可以防止我们用接口去试客户公司的员工 email,进而得到它们的员工组成信息。

系统平稳运行三个月。

我们发现,即使我们不通过编造大量 email 地址请求验证接口,快速猜出客户公司员工组成。每次用户使用我们的系统,需要输入有效的客户公司 email 验证。如果我们记录用户的 email,一段时间下来,还是能得到客户公司的员工组成信息。

也就是说,用户账号不能流经我们的系统。

于是我们提出,我们的前端页面拿到用户账号后,先进行 MD5 加密,加密后传入我们的系统,我们将 MD5 传给客户,客户进行比对,返回给我们是否账号属于客户的组织。

这样我们即使存储,存储的也是一堆 MD5,我们并不能反推出用户的组织都有哪些 email。

系统平稳运行三个月。

客户表示,即使我们对他们保证我们在前端页面拿到用户输入的账号后,立即转换成 MD5 传入我们的系统,也不能保证我们未来一定不会收集账号。

为了满足客户的需求,我们需要,用户的账号不能出现在我们系统的任何一个部分,也包括前端的输入框。

也就是说对客户而言,用户不能在我们的输入框中输入自己的账号。

同时对我们而言,我们需要一个信息,来标识用户的账号,而这个信息我们无法解密出有效信息。

用户不能在我们的输入框中输入账号,那一定只能在客户的页面中输入自己的账号。

我们需要一个信息,这个信息标识了用户的信息,但我们无法解密。

而我们这里也有一个输入框,原来输入的是用户账号,现在输入的是加密的信息。

那么流程就可以是

  1. 用户访问客户网站,输入账号
  2. 客户网站返回一串 MD5
  3. 用户将 MD5 复制粘贴到我们网站的原账号输入框
  4. 用户点击登录,我们将 MD5 传给客户认证接口,验证成功进入我们的系统

这里有个问题,就是用户此时需要用的是我们的网站,却需要打开客户的地址,因此可以增加一步:

  1. 用户访问我们的网站,我们的网站跳转到客户网站
  2. 用户在客户网站,输入账号
  3. 客户网站返回一串 MD5
  4. 用户将 MD5 复制粘贴到我们网站的原账号输入框
  5. 用户点击登录,我们将 MD5 传给客户认证接口,验证成功进入我们的系统

这里有一处可以自动化的地方:客户网站时可以返回 MD5 给我们的网站的,因此可以改为:

  1. 用户访问我们的网站,我们的网站跳转到客户网站
  2. 用户在客户网站输入框输入账号,客户网站认证成功后跳转我们的网站,带上 MD5
  3. 我们的网站将 MD5 传给客户网站进行认证,验证成功后进入我们的系统

这个方案对我们来讲,我们自始至终我们传递的是一个我们无法解密的字符串,解决了烫手的用户信息问题。
对于客户来讲,email 只在自己的系统中流转,不会泄露出去,email 本身带有的一些信息不会被外部获知到。对于用户来讲,原来的登录步骤是在我们的系统输入 email, 点击登录后进入我们的系统,现在登录我们的系统时,我们的系统会跳转到另一个页面,在那个页面输入账号后点击授权,会跳回到我们的网页,然后进入我们的系统。

实际的 OAuth 为了适应一些不安全的网络环境,增加了一些额外的字段或步骤,同时核心原理也是这样的。