Node.js 如何使用OAuth2客户端从Dialogflow实现中验证Google日历API?

Node.js 如何使用OAuth2客户端从Dialogflow实现中验证Google日历API?,node.js,google-calendar-api,google-oauth,google-authentication,dialogflow-es-fulfillment,Node.js,Google Calendar Api,Google Oauth,Google Authentication,Dialogflow Es Fulfillment,我正在尝试使用node.js、Dialogflow fulfillment和GoogleAppis客户端库构建Google日历助手聊天机器人,其中Dialogflow fulfillment托管在GCP中。我在使用OAuth客户端ID创建身份验证方法时遇到了一个问题。我的想法是,当用户在Google Chat中添加bot时,bot应该向他/她打招呼,并向用户请求定义范围的权限(在这种情况下,在用户的Google日历中创建事件)。我目前所做的是向用户发送一个链接,用户将在其中查看范围、批准范围并生

我正在尝试使用node.js、Dialogflow fulfillment和GoogleAppis客户端库构建Google日历助手聊天机器人,其中Dialogflow fulfillment托管在GCP中。我在使用OAuth客户端ID创建身份验证方法时遇到了一个问题。我的想法是,当用户在Google Chat中添加bot时,bot应该向他/她打招呼,并向用户请求定义范围的权限(在这种情况下,在用户的Google日历中创建事件)。我目前所做的是向用户发送一个链接,用户将在其中查看范围、批准范围并生成一个代码,但随后应将此代码传递回函数以获取令牌并设置凭据

有没有办法自动获取此代码并对用户进行身份验证

我的代码看起来是这样的(因为我做了所有的测试,所以有点凌乱):


您的思路是正确的,但是让用户直接转到OAuth链接意味着他们将获得代码,因此必须将其发送给您

相反,您可以将它们发送到站点上的页面,该页面将它们重定向到OAuth链接。您包含的重定向URI应重新重定向回您的站点。通过这种方式,您可以获得代码并在服务器上进行处理。一旦你完成OAuth舞蹈,你的网站会告诉他们他们已经授权你,可以继续聊天

const {google} = require('googleapis');
const {WebhookClient} = require('dialogflow-fulfillment');
const credentials = {"installed":{"client_id":"618408396856-vrd3it4s4nk19tlo7qrnbb51a9f8bq6t.apps.googleusercontent.com","project_id":"pg-xc-n-app-577847","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"d_qDDlFVBtllcotgn2xvc00N","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}};

//setting authentication details
const SCOPES = [
    'https://www.googleapis.com/auth/calendar.events',
    'https://www.googleapis.com/auth/spreadsheets'
    ];
const {client_secret, client_id, redirect_uris} = credentials.installed;
const authentication = new google.auth.OAuth2(
    client_id,
    client_secret,
    redirect_uris[0]
);
const url = authentication.generateAuthUrl({
    access_type: 'offline',
    scope: SCOPES
});

const calendarId = 'primary';
const calendar = google.calendar('v3');

process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements

exports.meetingRoomFulfillment = function meetingRoomFulfillment(req, res) {
    const agent = new WebhookClient({ request: req, response: res });
    console.log(`Intent ${((req.body.queryResult || {}).intent || {}).displayName}`);

    console.log(`Dialogflow Request body`, JSON.stringify(req.body));
    if (req.body.queryResult === undefined || req.body.queryResult.intent === undefined || req.body.queryResult.intent.displayName === undefined) {
        console.log(`Missing intent so cancelling fulfillment`);
        res.send({});
        return;
    }

    function authenticate(agent){
        agent.add(`To authenticate this app please visit the following url: ${url}`);
    }

    function authenticationCode(agent){
        const code = agent.parameters.authenticationCode;
        console.log('The code: ' + code);
        authentication.getToken(code, (err, token) => {
            if (err) return console.error('Error retrieving access token', err);
            authentication.setCredentials(token);
            retrievedToken = token;
            console.log(retrievedToken);
    });
        agent.add('Successfully authenticated!');
    }

  function makeAppointment (agent) {
    const dateTimeStart = new Date(agent.parameters.date.split('T')[0] + 'T' + agent.parameters.time.split('T')[1]);
    const dateTimeEnd = new Date(new Date(dateTimeStart).setHours(dateTimeStart.getHours() + 1));
    const appointmentTimeString = dateTimeStart.toLocaleString();
    const eventDescription = agent.parameters.text;

    // Check the availibility of the time, and make an appointment if there is time on the calendar
    return createCalendarEvent(dateTimeStart, dateTimeEnd, eventDescription).then(() => {
      agent.add(`Ok, let me see if we can fit you in. ${appointmentTimeString} is fine!. I am creating an event called: ${eventDescription}`);
    }).catch(() => {
      agent.add(`I'm sorry, there are no slots available for this period.`);
    });
  }
  let intentMap = new Map();
  intentMap.set('authenticate', authenticate);
  intentMap.set('authentication code', authenticationCode);
  intentMap.set('Make Appointment', makeAppointment);
  agent.handleRequest(intentMap);
}

function createCalendarEvent (dateTimeStart, dateTimeEnd, eventDescription) {
  return new Promise((resolve, reject) => {
      calendar.events.list({
        auth: authentication, 
        calendarId: calendarId,
        timeMin: dateTimeStart.toISOString(),
        timeMax: dateTimeEnd.toISOString()
        }, (err, calendarResponse) => {
        // Check if there is a event already in the calendar
        if (err || calendarResponse.data.items.length > 0) {
            reject(err || new Error('Requested time conflicts with another appointment'));
            console.log(err);
        } else {
            // Create event for the requested time period
            calendar.events.insert({ 
                auth: authentication,
                calendarId: calendarId,
                resource: {
                    summary: eventDescription,
                    start: {dateTime: dateTimeStart},
                    end: {dateTime: dateTimeEnd}
                    }
            }, (err, event) => {
                err ? reject(err) : resolve(event);
                console.log(err);
                }
            );
        }
    });
  });
}