为了限制数据的可访问性,用户模块是大多数系统必不可少的功能。 于是对于开发者来说,用户模块开发就成了一件重复度很高的事情。 对于重复度高的事情,我们自然而然想到的是抽取成公共服务(代码)。 比如设计一个统一的用户管理服务来处理,但似乎也会出现一些问题:
- 功能问题。有的只需要简单的登录、注册、管理(增删改查),有的还需要角色设置、授权管理。对于简单的需求会提供较多的冗余信息,而对于复杂的需求会频繁修改接口。
- 界面问题。不同系统UI风格不同,导致前端页面仍需要重新开发。
- 其它问题。需要单独部署服务,同时可能由于数据库不同也要修改。
最后的结果往往是对于不同的系统独立开发用户模块,或者集中依赖一个用户服务,然后再根据各个系统的需求去修改这个服务。
或许我们可以采取一种更高效的方式——使用第三方免注册登录。
第三方免注册怎么选
第三方免注册是指一些第三方网站基于 OAuth 2.0 提供的免注册接口,我们可以通过用户授权信息 提供免登录功能的第三方应用很多:GitHub、谷歌、微信、QQ、钉钉等。 如果系统本身对第三方的资源有需求,肯定优先使用对应的免注册服务,比如某个插件需要获取用户的 GitHub 账号信息,肯定选择 GitHub 免登录。 而无资源需求的系统一般会支持多种免注册 而我这次开发的项目是供公司同事使用的内部系统,对比之后选择钉钉,原因有下面2个:
- 钉钉是内部统一的通信软件,每个人都有钉钉账号。GitHub 账号就不适合,因为只有技术人员有。
- 可以从钉钉账号中获取用户部门、职位等信息,实现权限管理更容易。微信、QQ 等就无法提供此信息。
钉钉对于4种应用提供免注册功能:
- 企业内部应用。面向企业内部开发人员和定制服务商,自主开发内部应用或工作台,供企业或组织内部使用。
- 第三方企业应用。面向应用服务商,开发应用接入钉钉,管理员开通后,钉钉上的企业/组织即可使用。
- 第三方个人应用。面向应用服务商,开发应用接入钉钉,提供给钉钉个人用户使用。此类应用不需要管理员安装,个人即可直接使用。
- 移动应用接入。接入钉钉开放平台,让你的移动应用可以支持钉钉分享、钉钉帐号登录。
由于项目并不需要提供给其他企业应用,故第三方企业应用不适合,考虑到项目需要在 PC 端和移动端运行,所以开发成 HTML5 应用,放弃移动应用,采用第三方个人应用和企业内部应用。
登录流程
第三方个人应用(PC端免登录)
- 跳转到配置的URL1
- 用户扫码授权登录
- 跳转到配置的URL2
- 将URL2中的请求参数code传给服务端
- 服务端向钉钉服务器请求access_token
- 服务端通过access_token签名code发送给钉钉服务器,获取用户信息
企业内部应用(移动端登录)
- 浏览器调用钉钉 JSSDK 通过 corpId 获取code
- 浏览器将获取的 code 传给服务端
- 服务端向钉钉服务器请求access_token
- 服务端调用REST API获取用户信息
总结起来,大体流程一致,就是将浏览器端获取的code与服务端获取access_token发送给钉钉服务器获取用户信息。 获取code的过程在移动端较为简单,将corpId传入SDK调用函数即可,用户无需操作。PC端则需要两次跳转,需要用户扫码授权。 获取 access_token 则是通过创建应用时钉钉给出的 appKey 和 appSecret 换取。
具体实现
第三方个人应用(PC端免登录)部分 Python 代码:
- 通过 key 和 secret 获取 access_token。
def get_token():
pc_access_token_url = basename + 'sns/gettoken?appid={0}&appsecret={1}'.format(
cfg['pc_key'], cfg['pc_secret'])
r = requests.get(pc_access_token_url)
obj = json.loads(r.text)
return obj['access_token]
- 先通过 secret 将 timestamp 生成签名,将 key 和 签名、签名参数、浏览器传来的code发送给钉钉服务端获取用户信息。
def get_user():
user_info_url = basename + 'sns/getuserinfo_bycode?accessKey={0}×tamp={1}&signature={2}'
signature = base64.b64encode(hmac.new(bytes(
cfg['pc_secret'], 'utf-8'),
bytes(timestamp, 'utf-8'), hashlib.sha256).digest())
r = requests.post(user_info_url.format(cfg['pc_key'], timestamp, quote(
signature)), json.dumps({"tmp_auth_code": code}))
json.loads(r.text)
企业内部应用(移动端登录)部分 Python 代码:
- 通过 appId 和 secret 获取 access_token。
def get_token():
access_token_url = basename + \
'gettoken?appkey={0}&appsecret={1}'.format(
cfg['app_id'], cfg['secret'])
r = requests.get(access_token_url)
obj = json.loads(r.text)
return obj['access_token]
- 将 access_token 和 code 发往钉钉服务器获取用户信息。
user_info_url = basename + 'user/getuserinfo?access_token={0}&code={1}'
r = requests.get(user_info_url.format(rds.get('access_token'), code),
{'referer': cfg['redirect_url']})
return json.loads(r.text)
总结
采用第三方登录授权可以让用户跳过繁琐的注册、输入账号密码过程,提升用户体验的同时也减轻了开发压力,加快了项目进度。即使需要实现复杂的用户管理功能,也可以后期结合第三方信息进行开发。
原文链接:tech.gtxlab.com/dingding-au…
作者信息:朱德龙,人和未来高级前端工程师。