如何使用从 Alexa Smart Home Skill Directive 收到的 BearerToken 来识别使用 AWS Lambda 和 NodeJS 的用户电子邮件和个人资料?

Posted

技术标签:

【中文标题】如何使用从 Alexa Smart Home Skill Directive 收到的 BearerToken 来识别使用 AWS Lambda 和 NodeJS 的用户电子邮件和个人资料?【英文标题】:How to use BearerToken received from Alexa Smart Home Skill Directive to identify the user email and profile using AWS Lambda with NodeJS? 【发布时间】:2022-01-16 09:56:27 【问题描述】:

一些背景: 我正在使用 Amazon Alexa 智能家居技能来控制一些物联网设备,其中 AWS Lambda 函数用 NodeJS 编写作为默认端点。我已经将 Alexa Skill 与 lambda 函数相关联,创建了 Login With Amazon 安全配置文件,并为 alexa 技能启用了帐户链接。目前,我已经关闭了“发送 Alexa 事件”权限,因为这在响应事件方面增加了其自身的复杂性。目前我的技能处于 Beta 测试阶段。

我的用例:我有 3 个不同的客户,他们有不同的姓名、不同的电子邮件 ID 和不同的亚马逊帐户。所有 3 位客户都在他们的 Alexa 应用程序中下载了我的 Alexa 技能,并将其链接到他们的亚马逊账户。所有这些客户家里都有 2 台设备(灯和风扇),它们连接到我的云。我已将他们的设备信息与他们的电子邮件 ID 存储在我的云中的数据库中,如下所示:

    bob@gmail.com,灯 -> 开,风扇 -> 关 jhonny@gmail.com,灯 -> 关闭,风扇-> 关闭 alice@gmail.com,灯 -> 关,风扇 -> 关

现在假设其中一位客户 Jhonny 想要打开灯。因此,当 Jhonny 要求 Alexa 打开灯时,我的 lambda 函数将收到以下指令:


    "directive": 
        "header": 
            "namespace": "Alexa.PowerController",
            "name": "TurnOn",
            "payloadVersion": "3",
            "messageId": "003edc9f-68ad-4618-a982-f73fc37d25be",
            "correlationToken": "AAAAAAAAAQDaOl/vVaX+GlN2m9SvqFri/AEAAAAAAACdKWHpFqLjNmk4Y6DeNDRoGjdMODTZW6kkXKZoe3Ya289F45koL55JJmcv05BVBFceJH9FXOb/YJcwQH+xk4yx1KMa92zoBTl7jNayw8r4Pzfvd8oO486Fx3q3g35xAeNfNPbHalpV7ftYw86qXsurSfRkk2vgqWQu9CsYH013/fqY3ojnQySOIu31BAaiGWI4Pur4x/2zg3HOBKQkzguIMVmWxZP7de+VCoD5cqEQYOoE7ACQi6NAGPJHbS5cLY/2FBO163wLeDGoJZ8sfEcroQYpqGCkQ+KTLolZ2SDle2VvubB7Ntc0Rzpfg45dGFj6T2Mb8mP/PgxH+mfgTzjTUgTq9N6wfA/zAvXWnpCkC6/3nFUS3NzsYqaa+ff/Zm7smI645BJU6BJu19f6oRi4sjK+mqQLJDax9orIjrZ2Yd6ASq2Z31lZthgDFTyqe5b+JTP1Sp4j6S9uayIxyGj59eYxB1YMCxrm3clMJRKBphwiNrGewcGWZ2Qb2saB3Ctmy+fxPmasqFfbxnf4LYBib0VQrOpmvbRR8u3CT14ltCTubEA/iw2krMfqlM6xvzukFyRj++8oOfXNMGefGfe11GlcbDWXVDoJURbOjbaGGqks6jdZ0TOD/TxepHHnlBfWgHA9pfibikqBsB8NXvp"
        ,
        "endpoint": 
            "scope": 
                "type": "BearerToken",
                "token": "Atza|IwEBIAdKRpKJ5emckzWUGPRR-O9_Pg2mWV0BDxgfUCJbcqNNWSb8zfl4ueaG8eu-1YZOyA3qTyJVnn9X9JtYOfzcJClEROo1bDoGMs_VEeA-7aTZK5RKMWIHIbz8BIdmt6Ncr6bF8WkZnhNjS4q-qim4ICRfatrIaD2C0KXykXNJnYco11aSR7tGkhcwKm27jjPoewap2k07BqMhmaaB2ie_-v_2ojbDWmKW95MuCeYMoZmYTmNh4o4A5YH_UlFO9atUTjr9oA4ROwL_3R02Yi_VYRf8iZJCF4FmxiXRGGMqwEMF1KNeV6zcUFAjBIvSORAOpSO6iRySn9lZeAazywrdCIYBc8LFnDtGQIeYdKXSW39qYFbfC-Hy3RCJwuVPQPzS9jX99pyYZ0q1ZuRRUg"
            ,
            "endpointId": "Light",
            "cookie": 
        ,
        "payload": 
    

因此,为了打开 Jhonny 家的灯,我必须以某种方式使用 Alexa 指令中的 BearerToken 从 Amazon OAuth 提供商服务中检索 Jhonny 的电子邮件地址或用户 ID。那是对的吗?否则,我将不知道要更改数据库中的哪个条目。

现在我的问题是:如何使用此 BearerToken 来获取用户 ID 和其他信息?为此,我需要一些 NodeJS 中的示例代码,我可以在我的 Lambda 函数中实现这些代码。

【问题讨论】:

请编辑问题以将其限制为具有足够详细信息的特定问题,以确定适当的答案。 这个问题已经描述了一个非常具体的问题,而且我已经提供了足够多的描述,其简单性和长度即使是初学者也能理解这个问题。如果您仍然认为问题中需要添加或更新某些内容,请具体说明。 【参考方案1】:

我们可以通过使用承载令牌向主机发送 HTTP GET 请求来获取用户配置文件。下面的链接通过提供您的不记名令牌提供了一种漂亮且非常简单的方法来验证用户个人资料,并提供基本的理解。

https://reqbin.com/req/5k564bhv/get-request-bearer-token-authorization-header-example

如果您使用 Login With Amazon 作为您的 OAuth2.0 身份提供商,那么只需在上面的链接中提及以下项目:

主机网址:https://api.amazon.com/user/profile 选择授权 选择不记名令牌 复制从 alexa 指令接收到的不记名令牌并粘贴到框中(通常以 Atza|xxxyyyzzz 开头) 点击发送 如果您输入了正确的主机 URL、路径和不记名令牌,并且如果您的不记名令牌尚未过期,那么您应该会看到 200 响应代码以及用户个人资料详细信息,例如 user_id、姓名、电子邮件等。 如果您的不记名令牌已过期,您只需要求 Alexa 操作其中一台设备,并从 AWS CloudWatch 日志中获取新的不记名令牌进行验证。 Bearer Token 通常在 3600 秒后过期。

现在回答我最初的问题,这是一个使用 NodeJS 的 AWS Lambda 的简单代码 sn-p,它对我有用:

const https = require('https');

const handlerInput = 
    "directive": 
        "header": 
            "namespace": "Alexa.PowerController",
            "name": "TurnOn",
            "payloadVersion": "3",
            "messageId": "f8107929-cc45-4bfe-b7ae-eb9b61c09d5c",
            "correlationToken": "AAAAAAAAAQDaOl/vVaX+GlN2m9SvqFri/AEAAAAAAADsiP98Ew8DnuYv7JWgKtb4W/WFyycSA33aKocZD0AOnl5+PmKQuqgx2p/CT5Efln0lbORsb9jSB/zB9s3RLgO2dCG3B5/b6jzVzch98o3ULz61HgoAPz/ZsZIFWXyfqUhLrdwyggsnInsCOeUOHpRZ15VLJ6oEyW7zNE6MCfcH+SfPB2BMr7ex1wP3Ghz7fPNIwTeMhV/ZstF/mF7K74gH1psCLgGLzdc4YYtRtz7KxHCS3I8eUd2UQZ4NyCf9gVktphgTzXu6ezBp5qoexsmgkHQ0duK0zF2HoKvY8jhVD8MH2unJQLbcn5VQyMololRkQ3E1orZXy86t5Ls1ILC6qbtT1tKbeTqVChTBiCh5jczOuSW5mES+1fmhbBxx1HbE8OXhfSNcXcE2VAY49LTBafnUQ7NftkDTRRFJKgL+IIdBq283SgZNFWmJxwGBN5OXC5vKQGD1QzHUlhb91I9xQ1bmx9jKPP8tBj0ydkY/nD++34zQfxDObbX7cmVs4/4nTKNhm2o2RGZmVyMr6PzhvRzq777Vi+keJM+qXQxSRO0NzdSFWdBDBHCL46nAvwlOjNIvHsOoaODEVNK5HzT6a+H4PsbDazZgfXB4QFjIb9FvFZ6wmlGM1iOU/sN40ro3pQ12IE+Dn+tweemgRaRucn/mT0/E5IRgnliR"
        ,
        "endpoint": 
            "scope": 
                "type": "BearerToken",
                "token": "Atza|IwEBINNVA3FmduJsc_iA2Jpo2hBfl2XKPCzujkVWgix2TychTLTuAbnchakWuNiNGnpimsAx2dwoJCoUbarJXRv5a1ECrYoVi-SnAt6xxVvxi4CX4zd13rCq1wddl90Lp71bJDq9qfvlS-d9KillCwRYh4BBY0GegU16hM4RC07nBMvra07Dfe_kq9PIzu4yOeSaLwobiEAhNex3Qyo4n0jW6iyB5YzKUe2UAu0pQZmkeNjRmhPVpy0L4Pv539O87yXBT7iQ8pkhZBKeZWcuFltCN2_v1SfhMNQbnLlt_CMFry-eQg0t9oSaweCJOvrAYVKmg0cd-gNd27ttqZkmD0rMGERmTNkij_rTQJ9iiQKjEW1Xx_7TWVniqda1Hp_o1wA5p4aT6BYQKkoFrRm4pSa3iUA"
            ,
            "endpointId": "Light",
            "cookie": 
        ,
        "payload": 
    
;

exports.handler = async (event) => 
    // TODO implement
    const accessToken = handlerInput.directive.endpoint.scope.token;
    console.log(accessToken);
    const info = await getUserInfo(accessToken);
    console.log(`info: $JSON.stringify(info)`);
    const response = 
        user_ID: info.user_id,
        name: info.name,
        email: info.email,
    ;
    return response;
;

async function getUserInfo(accessToken) 
    return new Promise((resolve, reject) => 
        const options = 
            "method": "GET",
            "hostname": "api.amazon.com",
            "path": "/user/profile",
            "headers": 
                "Authorization": `Bearer $accessToken`
            
        ;
        let req = https.request(options, (response) => 
            let returnData = '';

            response.on('data', (chunk) => 
                returnData += chunk;
            );

            response.on('end', () => 
                resolve(JSON.parse(returnData));
            );

            response.on("error", (error) => 
                reject(error);
            );
        );
        req.end();
    );

确保将上面代码中的 handlerInput 替换为最新的副本。您可以在 Logs -> Log Groups 下从 AWS CloudWatch 获取它。

以下 YouTube 视频还包含有关创建技能、帐户链接和通过访问令牌识别用户的整个过程的非常有用的信息:

https://www.youtube.com/watch?v=NrBBM9XhzG0

很遗憾,该视频没有说明如何使用智能家居技能,尽管它非常相似。

【讨论】:

以上是关于如何使用从 Alexa Smart Home Skill Directive 收到的 BearerToken 来识别使用 AWS Lambda 和 NodeJS 的用户电子邮件和个人资料?的主要内容,如果未能解决你的问题,请参考以下文章

了解如何在 google home 设备中下载 javascript 代码,以便在本地家庭执行(google smart home 上的操作)

为 Screen Sample App 添加新的 Alexa 技能

您如何从 Alexa 设备获取原始语音输入

♥51单片机也可以实现一个小小的智能家居√(smart-home)♥

♥51单片机也可以实现一个小小的智能家居√(smart-home)♥

如何从 Alexa Lambda 函数调用 Web 服务