首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >GoogleActions帐户未链接但错误

GoogleActions帐户未链接但错误
EN

Stack Overflow用户
提问于 2017-11-04 15:13:34
回答 3查看 1.2K关注 0票数 3

我试图在我的nodejs谷歌助理应用程序(DialogFlow或API.ai和Google )上实现DialogFlow身份验证。

所以我跟踪了这个回答。但我总是得到“看起来你的测试oauth帐户还没有链接。”错误。当我试图打开调试选项卡上显示的url时,它会显示500个坏掉的url错误。

对话式全充填

index.js

代码语言:javascript
运行
复制
'use strict';

const functions = require('firebase-functions'); // Cloud Functions for Firebase library
const DialogflowApp = require('actions-on-google').DialogflowApp; // Google Assistant helper library

const googleAssistantRequest = 'google'; // Constant to identify Google Assistant requests

exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
  console.log('Request headers: ' + JSON.stringify(request.headers));
  console.log('Request body: ' + JSON.stringify(request.body));

  // An action is a string used to identify what needs to be done in fulfillment
  let action = request.body.result.action; // https://dialogflow.com/docs/actions-and-parameters

  // Parameters are any entites that Dialogflow has extracted from the request.
  const parameters = request.body.result.parameters; // https://dialogflow.com/docs/actions-and-parameters

  // Contexts are objects used to track and store conversation state
  const inputContexts = request.body.result.contexts; // https://dialogflow.com/docs/contexts

  // Get the request source (Google Assistant, Slack, API, etc) and initialize DialogflowApp
  const requestSource = (request.body.originalRequest) ? request.body.originalRequest.source : undefined;
  const app = new DialogflowApp({request: request, response: response});

  // Create handlers for Dialogflow actions as well as a 'default' handler
  const actionHandlers = {
    // The default welcome intent has been matched, welcome the user (https://dialogflow.com/docs/events#default_welcome_intent)
    'input.welcome': () => {
      // Use the Actions on Google lib to respond to Google requests; for other requests use JSON
      //+app.getUser().authToken
      if (requestSource === googleAssistantRequest) {
        sendGoogleResponse('Hello, Welcome to my Dialogflow agent!'); // Send simple response to user
      } else {
        sendResponse('Hello, Welcome to my Dialogflow agent!'); // Send simple response to user
      }
    },
    // The default fallback intent has been matched, try to recover (https://dialogflow.com/docs/intents#fallback_intents)
    'input.unknown': () => {
      // Use the Actions on Google lib to respond to Google requests; for other requests use JSON
      if (requestSource === googleAssistantRequest) {
        sendGoogleResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
      } else {
        sendResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
      }
    },
    // Default handler for unknown or undefined actions
    'default': () => {
      // Use the Actions on Google lib to respond to Google requests; for other requests use JSON
      if (requestSource === googleAssistantRequest) {
        let responseToUser = {
          //googleRichResponse: googleRichResponse, // Optional, uncomment to enable
          //googleOutputContexts: ['weather', 2, { ['city']: 'rome' }], // Optional, uncomment to enable
          speech: 'This message is from Dialogflow\'s Cloud Functions for Firebase editor!', // spoken response
          displayText: 'This is from Dialogflow\'s Cloud Functions for Firebase editor! :-)' // displayed response
        };
        sendGoogleResponse(responseToUser);
      } else {
        let responseToUser = {
          //richResponses: richResponses, // Optional, uncomment to enable
          //outputContexts: [{'name': 'weather', 'lifespan': 2, 'parameters': {'city': 'Rome'}}], // Optional, uncomment to enable
          speech: 'This message is from Dialogflow\'s Cloud Functions for Firebase editor!', // spoken response
          displayText: 'This is from Dialogflow\'s Cloud Functions for Firebase editor! :-)' // displayed response
        };
        sendResponse(responseToUser);
      }
    }
  };

  // If undefined or unknown action use the default handler
  if (!actionHandlers[action]) {
    action = 'default';
  }

  // Run the proper handler function to handle the request from Dialogflow
  actionHandlers[action]();

  // Function to send correctly formatted Google Assistant responses to Dialogflow which are then sent to the user
  function sendGoogleResponse (responseToUser) {
    if (typeof responseToUser === 'string') {
      app.ask(responseToUser); // Google Assistant response
    } else {
      // If speech or displayText is defined use it to respond
      let googleResponse = app.buildRichResponse().addSimpleResponse({
        speech: responseToUser.speech || responseToUser.displayText,
        displayText: responseToUser.displayText || responseToUser.speech
      });

      // Optional: Overwrite previous response with rich response
      if (responseToUser.googleRichResponse) {
        googleResponse = responseToUser.googleRichResponse;
      }

      // Optional: add contexts (https://dialogflow.com/docs/contexts)
      if (responseToUser.googleOutputContexts) {
        app.setContext(...responseToUser.googleOutputContexts);
      }

      app.ask(googleResponse); // Send response to Dialogflow and Google Assistant
    }
  }

  // Function to send correctly formatted responses to Dialogflow which are then sent to the user
  function sendResponse (responseToUser) {
    // if the response is a string send it as a response to the user
    if (typeof responseToUser === 'string') {
      let responseJson = {};
      responseJson.speech = responseToUser; // spoken response
      responseJson.displayText = responseToUser; // displayed response
      response.json(responseJson); // Send response to Dialogflow
    } else {
      // If the response to the user includes rich responses or contexts send them to Dialogflow
      let responseJson = {};

      // If speech or displayText is defined, use it to respond (if one isn't defined use the other's value)
      responseJson.speech = responseToUser.speech || responseToUser.displayText;
      responseJson.displayText = responseToUser.displayText || responseToUser.speech;

      // Optional: add rich messages for integrations (https://dialogflow.com/docs/rich-messages)
      responseJson.data = responseToUser.richResponses;

      // Optional: add contexts (https://dialogflow.com/docs/contexts)
      responseJson.contextOut = responseToUser.outputContexts;

      response.json(responseJson); // Send response to Dialogflow
    }
  }
});

// Construct rich response for Google Assistant
const app = new DialogflowApp();
const googleRichResponse = app.buildRichResponse()
  .addSimpleResponse('This is the first simple response for Google Assistant')
  .addSuggestions(
    ['Suggestion Chip', 'Another Suggestion Chip'])
    // Create a basic card and add it to the rich response
  .addBasicCard(app.buildBasicCard(`This is a basic card.  Text in a
 basic card can include "quotes" and most other unicode characters
 including emoji .  Basic cards also support some markdown
 formatting like *emphasis* or _italics_, **strong** or __bold__,
 and ***bold itallic*** or ___strong emphasis___ as well as other things
 like line  \nbreaks`) // Note the two spaces before '\n' required for a
                        // line break to be rendered in the card
    .setSubtitle('This is a subtitle')
    .setTitle('Title: this is a title')
    .addButton('This is a button', 'https://assistant.google.com/')
    .setImage('https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
      'Image alternate text'))
  .addSimpleResponse({ speech: 'This is another simple response',
    displayText: 'This is the another simple response ' });

// Rich responses for both Slack and Facebook
const richResponses = {
  'slack': {
    'text': 'This is a text response for Slack.',
    'attachments': [
      {
        'title': 'Title: this is a title',
        'title_link': 'https://assistant.google.com/',
        'text': 'This is an attachment.  Text in attachments can include \'quotes\' and most other unicode characters including emoji .  Attachments also upport line\nbreaks.',
        'image_url': 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
        'fallback': 'This is a fallback.'
      }
    ]
  },
  'facebook': {
    'attachment': {
      'type': 'template',
      'payload': {
        'template_type': 'generic',
        'elements': [
          {
            'title': 'Title: this is a title',
            'image_url': 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
            'subtitle': 'This is a subtitle',
            'default_action': {
              'type': 'web_url',
              'url': 'https://assistant.google.com/'
            },
            'buttons': [
              {
                'type': 'web_url',
                'url': 'https://assistant.google.com/',
                'title': 'This is a button'
              }
            ]
          }
        ]
      }
    }
  }
};

实际上,我在对话框流内联编辑器中部署了代码。但是不知道如何实现oauth端点,它应该是单独的云函数,还是必须包含在存在的云函数中。而且,我对oauth授权代码流将如何实际工作感到非常困惑。假设我们使用的是助手应用程序,一旦用户说"talk to foo app",它会自动打开用于oauth代码交换过程的web浏览器吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-11-04 17:35:18

回答你提到的在10月25日发布了一项更新,表明他们已经采取行动阻止您输入google.com端点作为帐户链接的auth提供者。似乎他们可能采取了其他行动来阻止以这种方式使用Google的auth服务器。

如果使用自己的auth服务器,错误500将指示oauth服务器上的错误,您应该检查oauth服务器的错误。

更新以回答其他一些问题。

但是不知道如何实现oauth端点

谷歌提供了一些指导(但不是代码),说明如何使用OAuth或授权码流来实现最低限度的授权码流服务,以及如何测试它。

它应该是一个单独的云功能,还是必须包含在现有的云功能中?

它应该是分开的--甚至可以说它必须是分开的。在隐式流和授权代码流中,您都需要提供一个URL端点,其中用户将被重定向到您的服务中。对于授权代码流,您还需要一个额外的web钩子,助手将使用它来交换令牌。

这些背后的功能需要与您为Dialogflow Web钩子所做的非常不同。虽然某人可能会创建一个处理所有不同任务的单一函数,但没有必要这样做。您将分别提供OAuth URL。

但是,您的对话框流webhook确实与您的OAuth服务器有一些关系。特别是,OAuth服务器交给助手的令牌将被返回给Dialogflow Web钩子,因此Dialogflow需要一些方法来基于该令牌获取用户的信息。有很多方法可以做到这一点,但只列举几种:

  • 令牌可以是一个JWT,并将用户信息作为声明包含在主体中。对话框流Web钩子应该使用公钥来验证令牌是有效的,并且需要知道声明的格式。
  • OAuth服务器和对话框流webhook可以使用共享帐户数据库,而OAuth服务器将令牌存储为用户帐户的密钥并删除过期密钥。然后,Dialogflow Web钩子可以使用它获得的令牌作为查找用户的键。
  • OAuth服务器可能有一个(另一个) webhook,其中Dialogflow可以请求用户信息,将密钥作为授权头传递并获得答复。(例如,这就是谷歌所做的。)

确切的解决方案取决于您的需求和您可以使用的资源。

而且,我对oauth授权代码流将如何实际工作感到非常困惑。假设我们使用的是助手应用程序,一旦用户说"talk to foo app",它会自动打开用于oauth代码交换过程的web浏览器吗?

广义地说-是的。细节是不同的(并且可以改变),但是不要太专注于细节。

如果您在扬声器上使用“助手”,将提示您打开Home应用程序,该应用程序应该显示一张卡片,上面写着Action需要什么许可。点击卡片将打开浏览器或网页的动作网站,以开始流程。

如果您在移动设备上使用“助手”,它会直接提示您,然后打开“动作”网站的浏览器或you视图,开始该流程。

第一流程主要包括:

  • 如果有必要,让用户对自己进行身份验证。
  • 让用户授权助手代表用户访问您的资源。
  • 然后,它用一次代码重定向到谷歌的服务器。
  • 谷歌的服务器就会有代码..。关上窗户。这就是用户所看到的范围。

在幕后,Google接受这段代码,并且由于您使用的是授权代码流,所以在令牌交换URL上将它交换为一个auth令牌和一个刷新令牌。

然后,每当用户使用您的Action时,它将向您的服务器发送一个auth令牌以及请求的其余部分。

请建议OAuth2配置所需的包

我做不到的事。首先,它完全取决于您的其他资源和需求。(这就是为什么StackOverflow不喜欢要求这样的建议的原因。)

有一些包可以让您安装OAuth2服务器(您可以搜索它们)。我敢肯定外面有人提供免费的服务,尽管我不知道任何即时的情况。最后,如前所述,您可以使用Google的指导编写一个最小的OAuth2服务器。

试图为谷歌的OAuth创建一个代理是.也许有可能..。不像最初看上去那么容易...很可能不像任何人都满意的那样安全.而且可能(但不一定)违反了谷歌的服务条款

我们不能用这种方法存储用户的电子邮件地址吗?

嗯,你可以把你想要的任何东西存储在用户的帐户里。但这是用户的帐户为您的行动。

例如,您可以代表用户访问Google,以获取他们的电子邮件地址或其他他们授权您使用Google的内容。您拥有的用户帐户可能会存储用于访问谷歌服务器的OAuth令牌。但是,您应该从逻辑上将其视为独立于助手用于访问服务器的代码。

票数 5
EN

Stack Overflow用户

发布于 2017-11-07 08:22:59

我的最小oauth2服务器的实现(适用于隐式流,但不存储用户会话)。

取自https://developers.google.com/identity/protocols/OAuth2UserAgent

代码语言:javascript
运行
复制
function oauth2SignIn() {
        // Google's OAuth 2.0 endpoint for requesting an access token
        var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

        // Create element to open OAuth 2.0 endpoint in new window.
        var form = document.createElement('form');
        form.setAttribute('method', 'GET'); // Send as a GET request.
        form.setAttribute('action', oauth2Endpoint);

        //Get the state and redirect_uri parameters from the request
        var searchParams = new URLSearchParams(window.location.search);
        var state = searchParams.get("state");
        var redirect_uri = searchParams.get("redirect_uri");
        //var client_id = searchParams.get("client_id");

        // Parameters to pass to OAuth 2.0 endpoint.
        var params = {
          'client_id': YOUR_CLIENT_ID,
          'redirect_uri': redirect_uri,
          'scope': 'email',
          'state': state,
          'response_type': 'token',
          'include_granted_scopes': 'true'
        };

        // Add form parameters as hidden input values.
        for (var p in params) {
          var input = document.createElement('input');
          input.setAttribute('type', 'hidden');
          input.setAttribute('name', p);
          input.setAttribute('value', params[p]);
          form.appendChild(input);
        }

        // Add form to page and submit it to open the OAuth 2.0 endpoint.
        document.body.appendChild(form);
        form.submit();
      }

这个实现不是很安全,但它是我作为助手的OAuth服务器工作的唯一代码。

票数 0
EN

Stack Overflow用户

发布于 2018-04-05 06:31:51

经过很长一段时间,我才能使它发挥作用。我们必须首先启用web钩子,并且我们可以看到如何在对话框流实现文档中启用web钩子,如果我们要使用Google助手,那么我们必须首先在集成中启用Google助手集成。然后按照下面提到的步骤,在google上的操作中链接帐户:

转到谷歌云控制台-> APIsand Services ->凭据-> OAuth 2.0客户端id -> Web ->注意客户端ID,客户端机密从那里下载json -从JSON记录项目id,auth_uri,token_uri ->授权重定向URL白色列表,我们的应用程序的URL ->在这个URL固定部分是https://oauth-redirect.googleusercontent.com/r/,并在URL->中附加项目id,保存更改

在google ->帐户上的操作链接设置1.格兰特类型=授权代码2.客户端信息1.填写客户id、客户端安全组、auth_uri、token_uri 2.输入auth uri作为https://www.googleapis.com/auth,token_uri作为https://www.googleapis.com/token 3.保存并运行4.在运行谷歌助手时会显示错误,但不要担心5.请回到助理设置中的帐户链接部分,输入auth_uri作为https://accounts.google.com/o/oauth2/auth,token_uri作为https://accounts.google.com/o/oauth2/token 6。将作用域设置为https://www.googleapis.com/auth/userinfo.profilehttps://www.googleapis.com/auth/userinfo.email,然后我们很好地运行。7.保存更改。

在主机服务器(Heroku)日志中,我们可以看到访问令牌值,通过访问令牌,我们可以获得有关电子邮件地址的详细信息。

将访问令牌附加到"token=“链接中,我们可以在生成的json页面中获得所需的详细信息。

代码语言:javascript
运行
复制
`accessToken = req.get("originalRequest").get("data").get("user").get("accessToken")
r = requests.get(link)
print("Email Id= " + r.json()["email"])
print("Name= " + r.json()["name"])`
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47112179

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档