技能授权
1.1. 符合 RFC6749 的 OAuth2.0
若琪智能家居技能授权支持符合 RFC6749 的 OAuth2.0 授权方式,目前只支持 AuthorizationCode Flow。
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI ---->| |
| User- | | Authorization |
| Agent -+----(B)-- User authenticates --->| Server |
| | | |
| -+----(C)-- Authorization Code ---<| |
+-|----|---+ +---------------+
| | ^ v
(A) (C) | |
| | | |
^ v | |
+---------+ | |
| |>---(D)-- Authorization Code ---------' |
| Client | & Redirection URI |
| | |
| |<---(E)----- Access Token -------------------'
+---------+ (w/ Optional Refresh Token)
上面这个图中的步骤解释:
(A) 客户端通过重定向用户的浏览器到授权页面启动授权流程。客户端会提供它的 client id,请求的授权范围,客户端状态码,和一个授权服务器会在授权完成后将浏览器重定向至URI。
(B) 授权服务器认证了用户之后,确认用户确实授权了这个客户端的访问请求。
(C) 假设用户授权了访问请求,授权服务器将浏览器重定向到之前的回调 URI,回调的 URI 包含一个授权码和之前客户端提供的本地状态码。
(D) 客户端通过在前一个步骤中获得的授权码从授权服务器请求 AccessToken。发起请求时,客户端会使用预定的认证方式认证客户端的身份,并提供获取授权码的回调 URI 作为验证。
(E) 授权服务器认证客户端,并验证授权码,保证回调 URI 与步骤 (C) 中获取授权码的回调 URI 相同。如果合法,授权服务器将一个 AccessToken 和一个可选的 RefreshToken 返回给客户端。
1.2. 基本接口
接入 OAuth2.0 需要实现两个接口:
1.3. AuthorizationCode 颁发
智能家居 Skill 需要提供 Authorization 页面供用户授权若琪使用他们的设备。若琪会构建一个在 Query 结构中包含以下参数的 URI,然后将用户重定向至这个授权页面:
- response_type: 值为
code
- client_id: 若琪所使用的标识
- redirect_uri: 回调地址https://homebase.rokid.com/oauth/callback
- scope: 授权的范围
- state: 用来保持授权请求和授权回调状态的值,当授权完成后需要将这个参数附加在回调里。
举个例子,若琪 App 会将用户的浏览器定向到下面这个 URL 上,
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
授权服务需要校验这个请求的参数是否合法的。如果是合法的请求,则授权服务需要对用户进行认证并获得用户的授权许可。 获得了用户的授权许可后,授权服务需要将用户使用 HTTP 重定向至指定的回调 URI。
1.4. Authorization Response
在获得了用户的授权后,授权服务需要颁发一个授权代码并使用包含以下参数的重定向 URI 将参数传递至若琪服务。
- code: 必须,一个由授权服务颁发的授权代码。推荐最长只有 10 分钟的寿命,并且不能使用多次。
- state: 必须,授权请求中的 state 参数
举个例子,授权服务将客户端重定向至以下地址:
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
1.5. AccessToken 接口
若琪服务会使用在请求体中包含以下参数的 HTTP 请求至 Token Endpoint 获取 AccessToken:
- grant_type: 必须,值为
authorization_code
,如果是刷新 Token 则为refresh_token
- code: 如果是通过
authorization_code
获取 access token 则为必须,授权过程中颁发的授权代码 - refresh_token: 如果是通过
refresh_token
获取 access token 则为必须,同 access token 一起获得的 refresh token - client_id: 必须,若琪所使用的标识
- client_secret: 可选,如果使用 HTTP Basic Auth 则该参数会包含在 HTTP Authorization Header 中
举个例子,若琪在获得了授权代码后,会使用以下 HTTP 请求获取 AccessToken:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
1.6. AccessToken Response
- access_token: 必须,由授权服务颁发的 access token
- expires_in: 可选,AccessToken 的寿命,以秒为单位,如果 access_token 会过期则应该必须提供
- refresh_token: 可选,用来通过以
refresh_token
的grant_type
请求 AccessToken 接口获取新的 AccessToken 的 token
一个成功的返回例子:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "2YotnFZFEjr1zCsicMWpAA",
"expires_in": 3600,
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter": "example_value"
}
1.7. 预注册参数
参数名 | 类型 | 注释 |
---|---|---|
authorizationEndpoint | URL | 授权地址 |
tokenEndpoint | URL | 获取 token 的地址 |
clientId | string | 代表若琪的 id |
clientSecret | string | 获取 token 时的密钥 |
scope | string | 授权时申请的权限范围 |
clientAuthType | enum: 'basic-auth', 'body' | clientSecret 需要以哪种方式提供给授权服务 |
1.8. 其他授权方式
如果通过「语控引擎接入」,授权部分无需通过 OAuth 2.0 协议,请参考:基于 JWT 签名的服务端授权;