簡體   English   中英

如何使用 OAuth2 客戶端從 Dialogflow Fulfillment 驗證 Google Calendar API?

[英]How to authenticate Google Calendar API from Dialogflow Fulfillment using OAuth2 Client?

我正在嘗試使用 node.js、dialogflow-fulfillment 和 googleapis 客戶端庫在 GCP 中構建具有 Dialogflow 實現的 Google 日歷助手聊天機器人。 我在使用 OAuth 客戶端 ID 創建身份驗證方法時遇到問題。 這個想法是當用戶在谷歌聊天中添加機器人時,機器人應該向他/她打招呼,並要求用戶對定義的范圍進行許可(在這種情況下在一個人的谷歌日歷中創建事件)。 我目前設法做的是向用戶發送一個鏈接,用戶將在該鏈接中看到范圍,批准這些范圍並生成代碼,但隨后應將此代碼傳遞回 function 以獲取令牌並設置憑據。

發送給用戶的鏈接

生成的代碼

傳遞給用戶的代碼

有沒有辦法自動獲取此代碼並對用戶進行身份驗證?

我的代碼看起來像這樣(由於我所做的所有測試,它有點亂):

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);
                }
            );
        }
    });
  });
}

您在正確的軌道上,但是讓用戶 go 直接訪問 OAuth 鏈接意味着他們將獲得代碼,因此必須將其發送給您。

相反,您可以將它們發送到您網站上的頁面,該頁面將它們重定向到 OAuth 鏈接。 您包含的重定向 URI 應再次重定向回您的站點。 通過這種方式,您可以獲得代碼並可以在您的服務器上處理它。 完成 OAuth 舞蹈后,您的網站會告訴他們他們已授權您並可以繼續聊天。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM