vlambda博客
学习文章列表

头号作家丨基于OAuth2.0的HeyTap运动健康开放平台授权鉴权方案设计

栏目介绍

“头号作家”是由OPPO工程师们解读时下热门技术的专题栏目。在这里,你不仅能看到最新最火的动态趋势,更能与OPPO的优秀工程师们共同学习技术干货。

头号作家

■ Terry

 热爱技术的后端开发一枚,喜欢分享,在微服务和DDD领域都有不错的实践。


01

背景


随着人们越来越关注自己和家人的运动健康,运动健康沉淀了大量高质量的用户数据。同时随着我们的运动智能设备使用的日益广泛,接入的外部渠道越来越多,迫切需要一套标准开放平台,方便各种设备接入和服务接入,加速健康的合作伙伴引入与落地。


02

行业常用授权鉴权方案


一般行业内通用的授权鉴权使用OAhth 2.0授权码的方式来实现。具体流程如下:

头号作家丨基于OAuth2.0的HeyTap运动健康开放平台授权鉴权方案设计

1.三方提供一个url,放在合适的位置,然后用户点击后调转到平台授权页。比如:

https://xxx.wanyol.com/open/v1/oauth/authorize?   response_type=code&   client_id=CLIENT_ID&   redirect_uri=CALLBACK_URL&   scope=read

其中response_type表示授权方式,code表示授权码,client_id是平台给三方的身份信息,用于标识是哪个三方,redirect_uri用户跳转回三方页面。scope标识请求的授权范围。

2.用户到了平台授权页后,需要用户登录平台账号,用户授权后服务端会生成授权码code,并通过redirect_uri返回。比如:

https: //open.gotoxxx.com/callback?code=AUTHORIZATION_CODE


3.三方拿到授权码后,根据授权码,请求平台的服务端获取token的接口,比如:

curl -X POST 'https://xxx.wanyol.com/open/v1/oauth/token' \     -d 'client_id=<CLIENT_ID>' \     -d 'client_secret=<CLIENT_SECRET>' \     -d 'grant_type=authorization_code' \      -d 'authorization_code=<AUTHORIZATION_CODE>' \     -d 'https://open.gotoxx.com/callback' 


4.三方获取token后将token放在请求头中,请求平台数据。

03

HeyTap运动健康开放平台


因为OAhth 2.0授权码的方式是经过广泛验证的有效方案,这里我们结合实际情况,采用Oauth2.0规范,H5授权+云云对接的方式来做,根据三方实际接入和使用场景来阐述具体的方案设计。

3.1 三方申请接入开发平台,需要提交必要资料,审核通过后发放client_id和client_secret。

client_id是用来识别三方的身份的,client_secret用于后面获取token,是三方证明“我真的是我”的凭证。这里特别注意需要三方提供回调域名,即redirect_uri,这是因为我们需要在授权的时候对回调地址做同源验证,防止攻击者篡改回调地址,让用户登录后生成的授权码返回到攻击者网站中。这个数据库模型如下:

头号作家丨基于OAuth2.0的HeyTap运动健康开放平台授权鉴权方案设计

3.2 三方应用在合适的地方,配置开放平台的H5授权页面。用户登录成功并勾选授权范围后,向三方返回授权码。

这里有两个重点需要注意下,一是权限,这里采用三级权限的设计,即系统权限,三方 应用权限,三方用户权限。范围逐渐缩小,系统权限,即开发平台系统所有可以对外提供的权限,比如读写用户基本信息的权限,读写用户运动数据的权限。三方应用授权是系统权限的子集,指的是针对具体的三方授予哪些权限,而三方用户权限是三方应用权限的子集,指用户勾选了哪些权限给三方应用。具体数据库模型如下:

头号作家丨基于OAuth2.0的HeyTap运动健康开放平台授权鉴权方案设计

二是授权接口。授权接口主要入参有三方clientId,redirectUrl,以及勾选的数据权限scopes和用户登录后的账号ssoid。其中clientId需要校验是否在开发平台备案,不存在不允许授权。redirectUrl表示授权后的回调地址,向3.1所说到的,这里必须做同源校验。还有一点需要声明,推荐三方应用的的回调地址使用state参数,state 参数是为了保证申请 code 的设备和使用 code 的设备的一致而存在的。开发平台回原封不动的返回。state规则生成复杂一些,攻击者就无从下手了。为了保证安全,授权码authorizationCode时效性只有五分钟。具体数据库模型设计如下:

头号作家丨基于OAuth2.0的HeyTap运动健康开放平台授权鉴权方案设计

3.3 三方调用接口用授权码(Authorization Code)获得 accessToken,同时获得一个用于刷新 accessToken 的 refreshToken。

三方获取授权码后,调用接口获取accessToken。接口入参如下:

头号作家丨基于OAuth2.0的HeyTap运动健康开放平台授权鉴权方案设计

特别注意,这个接口包含用授权码置换accessToken以及使用refreshToken刷新accessToken,clientSecret是必填的,也要和开放平台的clientSecret一致。出于安全性考虑,accessToken时效为24小时,refreshToken时效时间为30天(每次刷新时都会更新refreshToken为30天)。其中accessToken和refreshToken都包含一些特定的信息,通过AES256 GCM加密和BASE64生成的。

3.4 接口鉴权

数据授权我们说完了,那怎么做鉴权呢?怎么保证三方请求的是合法的,是在用户授予的权限范围内的呢?

三方获得accessToken后,请求平台接口数据时需要在请求头中带上accessToken,我们需要校验accessToken是否存在,存在需要校验是否失效,访问的接口在用户的权限范围内。很自然可以想到,在入口处,采用过滤器,拦截所有三方请求数据的接口(授权和获取token除外),做统一的鉴权处理。为了提供鉴权的效率,我们在3.3中将生成的accessToken放在redis缓存中,key=accessToken,value=用户信息,用户权限信息,accessToken失效时间。所以判断accessToken是否存在是否正确以及是否失效就很简单了,只需要从redis拿到信息做判断即可。

那怎么做用户权限的校验呢?因为我们使用RESTFUL风格的api,这里我采用在每个接口上标记权限注解的方式来做。具体做法是给每个接口备注上权限,然后再spring启动时通过postProcessAfterInitialization接口,将每个接口的url和对应的权限对应起来,放在map中。三方调用接口时,根据请求的url获取map中的权限范围,和redis中用户的权限范围做比对,这样就可以完成鉴权了。


推荐阅读