账户关联

当技能需要使用用户的其他系统信息(非百度系统)为用户提供服务时,需要将用户的DuerOS账号与其他系统的账户进行关联,以获取其他系统的信息。这就是账户关联。DuerOS支持技能将用户的DuerOS账户与用户的其他系统账号关联起来,使技能提供更多的服务。

例如,一个支持用户浏览其存储在Google上照片的技能,当用户发出“我要查看Google上照片”的请求时,技能首先需要登录用户的Google账户,获取到照片的访问权限,然后将照片展现出来。在这个过程中,技能需要获得用户Google账户的授权,将用户的Google账户与用户的DuerOS账户进行关联。

因此,当技能需要使用用户的第三方系统提供服务时,需要将在设备上登录的DuerOS账户和提供服务的第三方系统账户建立关联。本文主要描述了账户关联的流程及技能在账户关联中的配置。

说明:本文提及其他系统指非百度系统的第三方系统。当技能使用需要身份验证的系统资源时,才会进行帐户关联。其他情况下,技能不需要进行帐户关联,可以使用每个请求中提供的userId来标识用户。

目录

支持账户关联的技能类型

在技能开放平台上,仅自定义技能和智能家居技能会涉及账户关联功能,内容播报技能不涉及账户关联功能。

在自定义技能中,如果用户需要使用其他系统账户的功能,则需要将DuerOS账户与其他系统的账户进行关联。例如,当用户使用一个关于微博内容分享的自定义技能时,如果用户说“小度小度,查看我的关注”,此时技能会为用户展现微博的关注信息。在这个过程中,技能首先需要获取用户在微博账户的授权,然后才能登录用户的微博,获取微博的关注信息并展现。

在智能家居技能中,需要将用户的DuerOS账户与用户的设备云的账户进行关联,用户才能通过技能控制其设备云账户下的智能设备,如智能电灯、智能洗衣机等。

说明:在自定义技能中,用户在没有关联账户的时候,可以启用技能,只有请求服务过程中需要第三方系统验证身份时才会进行账户关联。在智能家居技能中,用户启用技能时就需要关联用户的设备云账户,否则无法启用技能。

如何进行账户关联

技能将用户的DuerOS账户与用户的第三方系统帐户关联时,需要第三方系统为该用户账户提供一个访问令牌,以便在第三方系统中唯一地标识用户。DuerOS保存访问令牌,并将令牌包含在发送给技能的请求中。技能使用访问令牌代表用户身份访问第三方系统,通过该系统的身份验证,进而获取到用户在该系统中的信息或者资源。

使用DuerOS提供的帐户关联功能需要熟悉OAuth 2.0授权

授权码模式

OAuth 2.0定义了四种授权方式。

  • 授权码模式(Authorization Code)
  • 简化模式(Implicit Grant)
  • 密码模式(Resource Owner Password Credentials Grant)
  • 客户端模式(Client Credentials)

DuerOS目前仅支持授权码模式(Authorization Code)的OAuth授权方式。

在授权码模式中定义的相关概念。

  • Resource Owner:资源所有者,这里指使用技能的"用户"。
  • Resource Server:资源服务器,即服务提供商存放用户生成资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。
  • Authorization Server:认证服务器,即服务提供商专门用来处理认证的服务器。
  • Client: 应用程序代表资源所有者(用户)向资源服务器发出请求。此处指技能。
  • access token: 访问令牌,用户在第三方系统中的唯一标识。
  • refresh token: 更新令牌,当访问令牌失效时,使用更新令牌重新获取访问令牌。

技能代表用户请求授权过程中涉及的参数:

  • response_type:表示授权类型,技能请求过程中使用固定值"code";
  • client_id:表示技能注册应用时获得的API Key。
  • ClientSecret:表示技能注册应用时获取的密钥。
  • redirect_uri:回调地址,表示用户授权后的重定向URI地址,由开放平台生成,每个技能的地址唯一。
  • scope:表示技能申请的权限范围。
  • state:表示客户端的当前状态,认证服务器会原封不动地返回这个值。

建立账户关联

建立账户关联的场景

建立账户关联主要有以下两种场景:

  • 在技能商店启用技能时要求用户绑定账号才能启用。
    智能家居技能属于这种情况。在启用技能时,需要用户进行账户绑定,技能才能控制相应的智能设备。
  • 在与技能交互过程中要求用户进行账户授权。
    自定义技能属于这种情况。当技能启用时,不需要用户进行账户绑定。只有当用户使用到账户相关的服务时,才需要账户关联。如社区新闻技能,用户不需要授权也可以浏览新闻,但是当用户想要发表评论时,技能需要用户登录授权才能发表评论。

建立账户关联的过程

不管是自定义技能,还是智能家居技能,不管是启用技能时授权,还是与技能交互过程中授权,授权的方式都是一样的,都是使用授权码模式。下面讲述账户关联的详细过程。

  1. 当需要用户授权时,会在屏幕或app(无屏设备启用技能时)上显示第三方系统的登录页面(即开放平台的填写的授权地址)。技能请求该授权地址时会携带state(必选)、client_id(必选)、response_type(必选)、scope(可选)和redirect_uri(必选)等参数信息。
  2. 用户在第三方系统的登录界面填写账户信息并进行登录授权。
  3. 第三方系统对用户的身份进行验证。通过身份验证后第三方系统会重定向到redirect_uri地址,并附上授权码。
  4. 重定向地址redirect_uri使用授权码向认证服务器(在技能开放平台上填写的token地址)申请令牌。
  5. 认证服务器核对授权码和redirect_uri,确认无误后,向DuerOS发送access token和refresh token。
  6. DuerOS验证返回信息,保存access token和refresh token。

经过上述操作,用户的DuerOS帐户已经关联到第三方系统的帐户,技能可以访问用户的第三方系统资源为用户提供服务。当用户请求技能时,DuerOS会携带access token信息,技能使用该access token代表用户访问第三方系统。

关联账户技能提供服务的过程

当技能完成用户的账户关联后,接下来是响应用户的服务。下面以微博内容分享的技能为例,讲述用户完成账户关联后,DuerOS请求以及技能响应的过程。

  1. 用户发出请求“小度小度,显示微博中我的关注”。
  2. 验证access token有效性。DuerOS确认需要使用用户唯一标识access token去请求技能进行处理,于是检查access token的有效性。
    • 如果已经保存access token,会对唯一标识用户的access token进行有效期校验。如果超过了有效期,则使用refresh token重新获取。
    • 如果DuerOS没有查询到access token,会通知技能,技能会返回LinkAccountCard,同时告诉用户完成账户关联。用户可以点击这个卡片,进入微博系统的认证页面进行授权,完成账户间的关联。
  3. DuerOS会向技能发送IntentRequest请求,并在请求协议中携带了access token。
  4. 技能收到IntentRequest请求后,验证访问令牌与微博系统中的用户账户是否匹配。当匹配成功时,技能访问用户在微博系统中的信息,并处理用户的请求。

禁用账户关联的技能

当用户禁用技能时,DuerOS将删除技能与该用户关联的访问令牌和刷新令牌,取消该用户的DuerOS账户与用户其他系统账户之间的连接。当用户再次启用技能时,需要重新将用户的DuerOS账户与提供服务的用户账户进行关联。

技能实现账户关联的过程

技能使用授权码模式(Authorization Code Grant)进行账户授权,在完成授权的过程中,技能需要做如下准备。

  • 提供第三方系统登录页面,用于完成用户第三方系统账户授权,实现账户关联。
  • 在技能服务中完成授权码的验证逻辑。
  • 在开放平台上配置授权信息。

下面主要介绍如何在开放平台上进行授权信息配置及登录页面的功能。

技能配置授权信息

如果技能需要使用用户授权功能才能提供服务时,需要在开放平台上填写相关的授权配置信息。

  • response_type:授权类型,取固定值code。
  • 授权地址:技能的授权地址。
  • Client_Id:客户端ID,技能在注册授权应用时获取的唯一标识。
  • ClientSecret:客户端的secret,技能在注册应用时获取的密钥。
  • Scope:权限范围。
  • 回调地址:重定向URL,有开发平台生成,每个技能拥有唯一的回调地址。
  • Token地址:获取Access token的地址,授权服务器。
  • 请求方式: 指token的请求方式,支持POST和GET两种请求方式。

images

登录页面的功能

当技能支持用户使用帐户关联功能时,技能需要设计、编写登录页面。该页面需要验证用户在第三方系统的登录信息,并返回访问令牌。如用户在技能商店app中启用智能家居技能时,会跳转到技能提供的第三方系统的登录界面。用户登录第三方系统进行访问授权,该页面验证用户的信息是否正确,正确时返回访问令牌。

登录页面接收的请求

用户在技能商店启用需要授权的技能时,会跳转到技能的登录页面,同时传递state、client_id、response_type、scope、redirect_uri等参数,参数具体解释如下。

  • response_type:表示授权类型,技能请求过程中使用固定值"code";
  • client_id:表示技能注册应用时获得的API Key。
  • ClientSecret:表示技能注册应用时获取的密钥。
  • redirect_uri:回调地址,表示用户授权后的重定向URI地址,由开放平台生成,每个技能的地址唯一。
  • scope:表示技能申请的权限范围。
  • state:表示客户端的当前状态,认证服务器会原封不动地返回这个值。

假设某技能的登录页面中使用的授权地址是https://www.yoursystem.com/login,DuerOS请求授权地址url的示例如下。

https://www.yoursystem.com/login?state=abc
&client_id=dueros-skill
&scope=read_basic_profile
&response_type=code
&redirect_uri=https://xiaodu.baidu.com/saiya/auth/20a400ef70c7fe9c1bbfea8741f291b7

登录页面的要求

登录页面需要满足以下要求。

  • 该页面基于HTTPS访问。
  • 该页面可以适配不同的设备,包括手机app、各种有屏设备端。
  • 该页面不允许出现任何弹出窗口。
  • 该页面必须接受用户的登录信息凭据,然后对用户进行身份验证。
  • 该页面需要能生成一个授权码code,该code可以传递到技能的授权服务器并返回access token访问令牌。
  • 该页面必须跟踪查询字符串中传递的state值,及原封不动的返回该state的值。
  • 该页面完成用户登录信息验证时,需要重定向到redirect_uri地址,同时携带参数state和授权码code。

账户关联示例

以微博授权为例讲解技能配置授权信息,及授权的流程。

假设现在有一个技能,该技能需要用户授予微博访问权限才能正常使用,技能需要在开放平台进行如下配置才能完成授权。

在开放平台上填写授权信息

开放平台上填写的授权信息,参数的含义及解释请参考技能配置授权信息

  • 填写client_id和client secret。 在微博开放平台注册应用,注册后可以得到App Key 和App Secret,分别对应client_id和client secret。
    image
  • 填写授权地址和获取授权地址(即Token地址)。 注册应用后,在微博API中找到请求授权接口地址和获取授权接口地址。
  • 请求方式选择POST方式。
  • 在微博应用中填写回调地址。当用户授权后需要微博授权服务重定向到回调地址,因此需要在技能创建的微博应用的高级信息里,添加授权回调页的地址(即回调地址),如图。
    image
  • 授权信息配置填写完成后,如下图所示。
    image
  • 在开放平台点击保存信息后,然后点击授权。
  • 出现授权页面后,点击授权。
    image

这里完成了技能在开放平台上授权信息的填写。

授权流程请求和回调请求

当用户进行授权时,DuerOS会向微博的请求授权接口发起请求,获取用户授权,请求示例如下。

https://api.weibo.com/oauth2/authorize?
client_id=255066862
&redirect_uri=https://xiaodu.baidu.com/saiya/auth/20a400ef70c7fe9c1bbfea8741f291b7
&response_type=code 

微博的授权接口完成授权后,会重定向到请求参数中的redirect_uri地址。通过回调将授权码返回给技能对应的回调地址,回调请求示例如下。

https://xiaodu.baidu.com/saiya/auth/20a400ef70c7fe9c1bbfea8741f291b7
?code=2e27ed623b5d534351d68351452d3172

其中必须传递的参数(code)位于URL的查询字符串部分,如果授权请求中携带了state参数,该回调地址会原封不动的回传该参数。

访问令牌和刷新令牌

在账户关联过程中,授权服务器需要提供一个唯一标识用户的访问令牌,技能需要通过该token访问资源服务器中该用户的信息。

DuerOS调用授权服务器的授权地址(在控制平台上配置的授权的地址),并传递code和客户端凭据。授权服务器获取到code后,会向配置的token地址获取access token的请求,并收到token地址返回的访问令牌(access token)和刷新令牌(refresh token),然后将访问令牌和刷新令牌返回给DuerOS。

在技能的回调地址获取到授权code之后,它会再向配置的token地址发送一个获取access token的请求,授权服务器收到该请求后的响应是返回access token和refresh token。

访问令牌的获取

在微博授权的技能中,回调地址在获取了授权码code后,会向微博的token地址https://api.weibo.com/oauth2/access_token发出post请求,请求中携带授权码code参数,token地址返回access token。获取access token的请求示例如下。

https://api.weibo.com/oauth2/access_token
grant_type=authorization_code
&code=2e27ed623b5d534351d68351452d3172
&client_id=255066862
&client_secret=0ef298f45910fc4e62f8f0e425fcd9e7
&redirect_uri=https://xiaodu.baidu.com/saiya/auth/12da329ff2b234522b0575a2ddb50ba7

token地址收到该请求后,会返回access token及refresh token信息,返回的请求示例如下。

{
    "access_token": "ACCESS_TOKEN",
    "expires_in": 1234,
    "refresh_token":"REFRESH_TOKEN"
}

授权成功再次回调redirect_uri地址,DuerOS就收到访问授权的access token。后续DuerOS向技能发送的请求中就会携带这个access token。

注意:access token的有效期由认证服务器设置,超过有效期access token需要重新获取。

刷新令牌的使用

用户授权成功后,授权服务器返回access token和refresh token。其中,access token是用户在该系统中的唯一标识,refresh token是指当access token过期时,可以使用refresh token作为参数去请求token地址,获取新的access token和新的refresh token。每个refresh token只能使用一次。

说明: 在oauth2.0授权码模式中,refresh token是可选的,这里refresh token必须存在。

技能验证访问令牌

当技能将用户的DuerOS账户与第三方系统账户进行关联时,技能需要编写逻辑来验证发送到技能的请求中包含的访问令牌,以及使用该access token去资源服务器中请求响应资源或者数据。

当技能完成账户关联后,需要对用户发送的请求进行验证,验证access token是否正确,然后使用该accss token去获取资源服务器中请求响应的资源。包括以下步骤。

  • 从DuerOS请求中获取access token
  • 验证access token有效性
  • 处理无效的access token
  • 需要验证access token的场景

从DuerOS请求中获取访问令牌

当技能完成账户关联后,DuerOS发送给技能的请求中会携带access token信息。下面是自定义技能的request请求示例,技能可以context字段中获取到用户的access token信息。

{
    "version": "v2.0",
    "session": {},
    "context": {
        "System": {
            "user": {
                "userId": "{{STRING}}",
                "accessToken": "21.0c024f408acab41ad1335d83fef805c9.2592000.1529823053.1884613120-11292535",
                "userInfo": {
                    "account": []
                }
            },
            "application": {
                "applicationId": "{{STRING}}"
            },
            "apiAccessToken": "eNlTLjIbRNu5MrRdtPjF7uvJq0AVPgMMTx8EO8gmfHnpVPT+bw0LNO89HxmNQj5bl9U436B4KfWGh41LMaQgZYqa4yqgXq0mdNbhixmrSnGb6FZNiVc3mmCeO9dbRu8TxPIG32Q4JRYZUTbhBrKuYtNmIj8OA1XZyXJ16Stow4c4hQB2U9KwLA3Li8k+E1Nz+QEoMx5CXibs194uGUbuiPmtb2xNJKWpbwjR4wKM6t68pNpQFbz8MlC/ZREHP2N9JjSeMmUvygerZskrPO2QzgstLiJHeRyjXrW64qHNJnUAGO+Jt8sRThOyCMK1OWRU",
            "apiEndPoint": "https://xiaodu.baidu.com"
        }
    },
    "request": {
        "type": "LaunchRequest",
        "requestId": "7a8efe366f464da190ed09c4f29f938f_0",
        "timestamp": "1527231426",
        "dialogRequestId": "755e1db3-b8fc-4d0a-9fec-68f11bf1cde9"
    }
}

在SDK中提供了获取access token的API接口。下面以java-bot-sdk为例,演示获取DuerOS发送的request请求中的access token信息。

@Override
protected Response onLaunch(LaunchRequest launchRequest) {
    Context context = getRequest().getContext();
    String accessToken = context.getSystem().getUser().getAccessToken();
    ...    
}

验证访问令牌有效性

技能收到DuerOS请求获取到access token后,需要对access token进行验证,只有access token正确有效,技能才会处理该请求。验证过程中可能会出现以下情况。

  • 请求中access token信息有效
    技能正常处理该请求,使用access token从资源服务器中访问数据。
  • 请求中的access token信息无效
    当access token信息无效,技能无法访问资源服务器。无效原因很多,可能是因为用户删除技能或者取消关联账户,也可能是access token过期。
  • 请求中不包含access token
    如果获取到的access token为空,表示并没有进行账户关联。

处理无效的访问令牌

当技能发现访问令牌access token无效或不存在时,可以通过以下方法提示用户进行账户关联。

  • 输出语音信息告诉用户,需要用户授权才能使用该功能。
  • 返回一个LinkAccountCard卡片让用户重新进行账号关联。 当该卡片在有屏设备端或app中显示时,用户点击该卡片即可跳转至相应的登录界面,进行登录授权。

技能响应示例如下。使用SDK提供的API接口返回LinkAccountCard卡片,并输出语音信息。

@Override
protected Response onLaunch(LaunchRequest launchRequest) {
    LinkAccountCard card = new LinkAccountCard();
    // 新建返回的语音内容
    OutputSpeech outputSpeech = new OutputSpeech(SpeechType.PlainText, "你必须先登录才能使用该技能,请先前往app进行登录授权");
    // 构造返回的Response
    Response response = new Response(outputSpeech, card);
    return response;
}

技能返回的response数据(仅列出部分信息)。

{
    "context": {
        "intent": null
    },
    "session": {
        "attributes": {}
    },
    "response": {
        "needDetermine": false,
        "fallBack": false,
        "outputSpeech": {
            "type": "PlainText",
            "text": "你必须先登录才能使用该技能,请先前往app进行登录授权",
            "ssml": ""
        },
        "reprompt": null,
        "resource": {
            "entities": null
        },
        "card": {
            "type": "LinkAccount"
        },
        "directives": [],
        "shouldEndSession": false
    },
    "version": "2.0"
}

在大多数情况下,此时的响应应该结束会话,shouldEndSession应该为true,因为用户在将其帐户连接到一起之后不能继续请求。如果技能包括一些不需要认证的意图,可以不关闭会话,保持会话打开,在未进行账号关联的情况可以使用不需要认证的意图。

需要验证访问令牌的场景

当技能将用户的DuerOS账户与技能服务的账户进行关联时,如果用户发出请求,技能会验证请求中的access token信息,保证信息的准确性。在以下场景下会验证access token。

  • 智能家居技能会对用户发出每一个请求的access token进行验证。
  • 自定义技能只在有的需要账户关联才能正常使用的意图中验证access token。其他情况不验证。