系统服务化构建-两方OAuth

鉴于微博,QQ,微信等开发平台的影响,互联网界的工程师都知道OAuth协议,对Token 存储用户信息的机制有所了解,却很少有人提及两方OAuth这个概念。

两方OAuth

说到OAuth协议,潜意识里都会想到涉及认证,客户,和服务器,进而是认证服务器,客户端应用和资源服务器三方。

现在通用的OAuth协议是OAuth2.0,是一个互联网开放授权协议,用于规范资源服务器,客户端应用,授权服务器三者的职责,实现客户端应用在不直接获取到普通用户的用户名和密码的前提下,访问用户的私有资源。

在实际应用开发过程中,我们的应用复杂性没有达到一定规模时,应用程序只涉及到客户端APP和服务器端中心云服务的认证和业务处理。我们可以对OAuth2.0协议进行简化,演变为两方OAuth。

Auth-history.png

上图[Auth-history.png]是几个服务器客户端验证的阶段。

OAuth 协议更多的可以理解为是一个宽泛的协议,在工程应用方面只关注规范,不要求细节。
最初的OAuth协议是服务器根据HTTP 协议头的Authorization 字段验证客户端身份。而如今逐渐演变成使用Token 的方式标记客户端身份,存储用户状态信息,至于Token如何生成,在HTTP 协议中如何传输,并没有过多硬性要求。

消费者APP

在OAuth协议体系中,消费者是指开发者开发的APP,这里的APP 更是一个广义的概念,不局限在安卓和iOS应用这两种类型。PC网站,移动端WebView也被认为是APP

服务端,各种云平台如何识别这些应用,借助于应用编号和应用密钥机制,应用编号就是APP_ID,或者APP_KEY,用于唯一识别应用。密钥就是APP_SERCRET,用于请求签名等安全算法的入参,和服务器端验证的凭据。

APP_KEY和APP_SERCRET的分配和管理是实现两方OAuth的第一步

读到这里,或许你有疑问了,上文说到的不同APP,无非是安卓,iOS,WebView,我们何不定义不同的枚举来标明不同的客户端,甚至可以使用User-Agent判断。

1 PC,2 安卓 3 iOS 4 微信

这样的分类可以解决吗,答案是很难。

实际上这是两个概念,从操作系统的角度划分更多的是一种数据来源渠道的概念,而APP_KEY的本质属性是接入云端平台的开发者应用标记。

Token 生命周期

以下是一个简版的Token生命周期模型

分配

Token由客户端发起,服务器云端负责分配,典型的场景,在用户登录成功后分配,一定有效期内过期,支持每次请求不一致,token滑动过期机制。默认30分钟失效。

生成规则

用户标记key: userid+应用编号。md5(userid+盐钥+时间戳) 盐值固定。生成规则可以根据项目个性化调整,Token值不可逆。

存储

服务器端 key value形式存储到redis中,key为token,value为加密值
客户端 Token,按需存储在本地,后续接口调用时使用

失效

过期时间内失效,如初始分配60分钟,那60分钟后自动生效。
退出时,需要调用接口,删除Token。

这里会引出一个思考

退出功能需要网络支持吗?

这个问题的缘由是我发现有些工程师,退出功能是这么做的,页面跳转,清除本地Token。

Token代表的是用户状态,这种状态代表的是客户端与服务端的一种关联关系,退出功能是切断这种关联。

HTTP 是无状态的,单纯的做请求响应,而业务必须是有状态的,否则业务无法流转和推进,这种状态交给Token负责,二者是如何关联的。是Token设计中需要考量的。

一个相对完整的Token落地机制是实现两方OAuth的第二步

签名算法

签名(Sign)用于保证数据的真实性和完整性,从时效,合法性,频率几个维度处理。

对所有待签名参数按照字段名的ASCII码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value​1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符,最后加&secret=app_secret; 对string1作签名算法,字段名和字段值都采用原始值不进行URL转义。具体签名算法为sign = md5(string)。
除登录外所有接口,由服务端决定开启或者关闭签名验证。业界叫验签。

签名就用到了APP_SECRET

sign-token.png

设计要点

采用前后端分离,将接口参数分为系统级别参数和业务级别参数。
系统级参数主要包括app_key,timestamp,token,os_type,sign,主要置于HTTP 请求头位置。
业务参数基于业务需求,采用POST 或者GET方法按需传递。

检测请求超时

通过客户端时间戳timestamp,来确定真正的客户端发起时间。
服务器端检测时间差,客户端请求时间与服务器时间的差值与超时时间做对比。例如,我们可以约定时间差大于5分钟间隔的请求为无效请求,或者超时请求。

识别终端

使用App-Key的方式识别应用终端,企业内部不同的应用,由云端服务统一管理。

场景1

进行个性化配置 ,来自于微信公众号的登录用户的过期时长设置为一天,而来自于PC官网的用户的登录过期时长设置为一周。
场景2

公司某个产品线的普通版和定制版的区分,使用App-Key,对功能的简易复杂度,收费模式做梯度设置。

场景3

应用于SASS应用识别,多租户数据隔离,在数据库对应用数据做隔离。进而为相关的运营数据分析提供支持。

其它设计规约

1 后台配置关闭启用开关,开发阶段可以关闭验证,建议开启。
2 启用验证后,前端需要有公共方法计算请求签名。后台需要增加安全验证模块验证请求合法性,负责登录过期失效检测,参数完整性和权限验证。
3 安全方面关注安全弹性,安全验证级别通过timestamp, sign, token参数,三个维度配合,逐层升级。通过增加验证条件和复杂性增强安全级别。安全级别做到合理即可,没有一概而论。

总结

以上给出了一套基于两方OAuth方式的云端,客户端服务设计模型。在应用服务不复杂,业务场景允许的前提下,使用两个OAuth方式,伴随着业务发展,可以逐步演化为基于三方身份的OAuth协议工程实现。
Token机制和签名机制也可以 独立分层,与业务应用分离,演化为网关系统。
这样的设计符合架构领域的简单,演化原则,是一种很实惠的应用架构方案。


图南日晟.jpg

阅读 847

推荐阅读
图南科技
用户专栏

分享,记录工作学习过程中的收获,心得,体会。主要涉及分布式系统设计,MoongoDB,消息队列,PHP技术栈...

749 人关注
16 篇文章
专栏主页