设备码模式
有些客户端所在的环境是没有浏览器的。例如:COZE(扣子)、智能电视、媒体控制台、数字相框、打印机等,像这类的设备,要在设备上将用户操作引导至认证平台界面去扫码登录,或者输入账号和密码,然后确认授权,这显然不现实。解决这类设备的登录场景,最常见的就是手机扫码登录,或将认证地址发送到手机上,让用户在手机浏览器上进行认证授权。在 OAuth 2.1 中,已经加入设备授权码模式,那么本篇就来实现一下设备授权码登录。
用户在COZE(扣子)进行公司用户的认证授权流程,如果没有认证,就会输出消息,引导点击链接或者生成二维码进行扫码,完成认证就可以开始后续的对话联系了。

OAuth2.1简介
Section titled “OAuth2.1简介”OAuth2.1的设计背景,在于允许用户在不告知第三方自己的账号密码情况下,通过授权方式,让第三方服务可以获取自己的资源信息。 详细的协议介绍,开发者可以参考The OAuth 2.1 Authorization Framework,以及OpenID Connect Core 1.0 incorporating errata set 2。
设备码模式接入流程
Section titled “设备码模式接入流程”
以上图交互比较多,但是对于设备终端来说,只要关注两个步骤:
1、图中步骤1,获取设备码;
2、图中步骤5,轮询请求,间隔5秒,获取access_token;
其他所有交互,企业服务平台已经实现,设备终端不需要关注。
请求方式: POST(HTTPS) Content-Type: application/x-www-form-urlencoded
请求地址: /oauth2/device_authorization
详细说明开发者可以参考The OAuth 2.1 Authorization Framework
| 参数 | 必须 | 说明 |
|---|---|---|
| client_id | 是 | 企业服务平台分配的client_id |
| scope | 否 | 授权范围,最小权限原则 |
| 参数 | 说明 |
|---|---|
| user_code | 用户码 |
| device_code | 设备码 |
| verification_uri_complete | 用户码验证地址,包含用户码参数 |
| verification_uri | 用户码验证地址 |
| expires_in | 设备码有效期,单位为秒 |
| error_description | 错误描述 |
| error_code | 错误码 |
| error_uri | 错误详细说明地址 |
a) 成功返回示例如下:
{ "user_code": "QWFN-VTLP", "device_code": "sf1NvQqp3A5kmSzfTW30UwrIlz_Ey4cFyomduHY8VtOZkQ3CnYsnwAwZROiJEpxr8tIEMJ4WDgC4rookrJCZ732KEmErF6UujpiI4_eBRDFXmWH3hQpGg-FdkDwPkRCw", "verification_uri_complete": "https://uat-esp.xkw.cn/oauth2/device_verification?user_code=QWFN-VTLP", "verification_uri": "https://uat-esp.xkw.cn/oauth2/device_verification", "expires_in": 300}b)失败返回示例如下:
{ "error_description": "client_id不正确", "error_code": "100031", "error_uri": "https://esp.xkw.cn/doc/error?q=error_code"}设备码缓存机制
Section titled “设备码缓存机制”接口返回device_code有效期为expires_in,单位是秒,调用方要做好device_code的缓存处理,
缓存时间 = expires_in - 60缓存时间只要将平台返回的expires_in减去1分钟即可。
注意:不要频繁请求获取device_code,以免被限流控制;
轮询请求,获取access_token
Section titled “轮询请求,获取access_token”注意:间隔2~3秒,比如5秒,间隔时间不要太短,没有必要,用户的交互需要一定的时间。
请求方式: POST(HTTPS) Content-Type: application/x-www-form-urlencoded
请求地址: /oauth2/token
详细说明开发者可以参考The OAuth 2.1 Authorization Framework
| 参数 | 必须 | 说明 |
|---|---|---|
| client_id | 是 | 企业服务平台分配的client_id |
| grant_type | 是 | 当前值为urn:ietf:params:oauth:grant-type:device_code |
| device_code | 是 | 设备码,上一步返回 |
| 参数 | 说明 |
|---|---|
| access_token | 访问令牌,调用开放接口的凭证 |
| refresh_token | 刷新令牌,在refresh_token有效期内,都可以对access_token进行刷新 |
| scope | 授权范围,返回构造的授权链接请求中的scope |
| token_type | token类型 |
| expires_in | access_token有效期,单位为秒 |
| error_description | 错误描述 |
| error_code | 错误码 |
| error_uri | 错误详细说明地址 |
a) 成功返回示例如下:
{ "access_token": "eyJraWQiOiJjM2Q2ZDAxYiIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJ4eTA3NjE5IiwiYXVkIjoiZGV2aWNlIiwibmJmIjoxNzE3ODQwNDM0LCJzY29wZSI6WyJvYSJdLCJpc3MiOiJodHRwczovL2VzcDIuZG9jLnhrdy5jbiIsImV4cCI6MTcxNzg0NDAzNCwiaWF0IjoxNzE3ODQwNDM0fQ.H-8COli2z-SmOwmdGII2qEOrg8tNygECB_LgO9ilQD2HguhLo310tvFzCUdoXVmcn1QBbs_JFjYr2DwEkvtgz9r_mvuwizVtgxbHsd1vh76xU7UH9_jHxWRkpoqQ5pdHB44-LjK5e15DgJ22sNs1HV0ouVNzDdLhdrvSj2_n8m_QEUf9xf-vQvTrHyx-KkatiFcDq2OxnFsQlikoMVvvYiOpsOumwemjCPVMThwF86vQ_PJ0E_PioOj9qnnBCqDF5xvPPGQMkAR_J1DVCg3uxd5u6-Npb0PHpfCvhPvrAHq44P_EvEhZge8WxWaAqdfOxgT9pCyCGol8kDoAz0jFmQ", "refresh_token": "Np4qZKiC1-ChAeA6KwclIpEd72frn6afBj6KyrFGEIDeKtVCzerUIqTs1uwAWdrbhW1qXg7Qxx19pmIkLbHuKlSROToWOO5GCPC_Jf44NysVeyzlD8bfnRtyDMrAHFuT", "scope": "oa", "token_type": "Bearer", "expires_in": 3584}b)失败返回示例如下:
{ "error_description": "client_id不正确", "error_code": "100031", "error_uri": "https://esp.xkw.cn/doc/error?q=error_code"}企业服务平台和接入的企业内部应用系统的接口请求,均可通过access_token来获取成员的身份信息。
查看access_token内容
Section titled “查看access_token内容”这里就要使用到时返回的access_token,解析后内容如下:

以上access_token中的sub就是用户ID,接口调用方不需要验证,如果需要调用企业服务开放接口或企业内部应用系统时,由对接的应用系统(接口提供方,详情查看“开放接口”说明文档)在接收到请求时,使用平台公钥进行验证;
授权范围说明
Section titled “授权范围说明”以上内容解析出来,scope值仅仅是oa,只是一个例子,可以为空,目前企业服务平台仅认证,不授权。后续升级使用会统一通知。
调用方Token缓存机制
Section titled “调用方Token缓存机制”接口返回access_token有效期为expires_in,单位是秒,调用方要做好token的缓存处理,
缓存时间 = expires_in - 60 * 10缓存时间只要将平台返回的expires_in减去10分钟即可。
注意:不要频繁请求获取access_token,以免被限流控制;
调用方接口请求
Section titled “调用方接口请求”在http请求的header部分,增加以下内容,key为Authorization,value为”Bearer ” + access_token值
| key | Value |
|---|---|
| Authorization | Bearer eyJraWQiOiJjM2Q2ZDAxYiIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJ4eTA3NjE5IiwiYXVkIjoiZGV2aWNlIiwibmJmIjoxNzE3ODQwNDM0LCJzY29wZSI6WyJvYSJdLCJpc3MiOiJodHRwczovL2VzcDIuZG9jLnhrdy5jbiIsImV4cCI6MTcxNzg0NDAzNCwiaWF0IjoxNzE3ODQwNDM0fQ.H-8COli2z-SmOwmdGII2qEOrg8tNygECB_LgO9ilQD2HguhLo310tvFzCUdoXVmcn1QBbs_JFjYr2DwEkvtgz9r_mvuwizVtgxbHsd1vh76xU7UH9_jHxWRkpoqQ5pdHB44-LjK5e15DgJ22sNs1HV0ouVNzDdLhdrvSj2_n8m_QEUf9xf-vQvTrHyx-KkatiFcDq2OxnFsQlikoMVvvYiOpsOumwemjCPVMThwF86vQ_PJ0E_PioOj9qnnBCqDF5xvPPGQMkAR_J1DVCg3uxd5u6-Npb0PHpfCvhPvrAHq44P_EvEhZge8WxWaAqdfOxgT9pCyCGol8kDoAz0jFmQ |