验证对话框:
import { ChoicePrompt, DialogSet, DialogTurnStatus, OAuthPrompt, TextPrompt, WaterfallDialog, ComponentDialog } from 'botbuilder-dialogs';
import GraphClient from '../graph-client';
const MAIN_WATERFALL_DIALOG = 'mainWaterfallDialog';
const OAUTH_PROMPT = 'oAuthPrompt';
const CHOICE_PROMPT = 'choicePrompt';
const TEXT_PROMPT = 'textPrompt';
import moment = require('moment');
class AuthDialog extends ComponentDialog {
constructor() {
super('AuthDialog');
this.addDialog(new ChoicePrompt(CHOICE_PROMPT))
.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.ConnectionName,
text: 'Please login',
title: 'Login',
timeout: 300000
}))
.addDialog(new TextPrompt(TEXT_PROMPT))
.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.promptStep.bind(this),
this.processStep.bind(this)
]));
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}
/**
* The run method handles the incoming activity (in the form of a TurnContext) and passes it through the dialog system.
* If no dialog is active, it will start the default dialog.
* @param {*} turnContext
* @param {*} accessor
*/
public async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
public async promptStep(step) {
return step.beginDialog(OAUTH_PROMPT);
}
public async processStep(step) {
if (step.result) {
// We do not need to store the token in the bot. When we need the token we can
// send another prompt. If the token is valid the user will not need to log back in.
// The token will be available in the Result property of the task.
const tokenResponse = step.result;
// If we have the token use the user is authenticated so we may use it to make API calls.
if (tokenResponse && tokenResponse.token) {
await step.context.sendActivity(`Logged in.`);
} else {
await step.context.sendActivity('something wrong happened.');
}
} else {
await step.context.sendActivity('We couldn\'t log you in. Please try again later.');
}
return await step.endDialog();
}
}
export default AuthDialog;
我有一个连接到luis的主目录,并根据识别的意图执行相应的代码:
例如,在某些情况下,我拥有这个:
case 'CalendarEvents':
return stepContext.beginDialog('AuthDialog');
const calendar = await new GraphClient('token').events();
let eventsBuilder: string = '';
// tslint:disable-next-line: prefer-for-of
for (let index = 0; index < calendar.length; index++) {
const element = calendar[index];
eventsBuilder += '\r\n' + moment(element.start.dateTime).format('dddd, MMMM Do YYYY, h:mm:ss a') + ' - ' + element.subject;
}
await step.context.sendActivity(`${eventsBuilder}`);
因此,如果意图是CalendarEvents,则进行身份验证,然后进行一些图形API调用。
我目前遇到的问题是,对图形api的调用是在身份验证完成之前进行的,我希望第一个用户进行身份验证,然后接收一些令牌,然后使用该令牌来获取图形api的调用!
任何想法如何实现以上目标?
请参阅Graph Auth Sample。特别是
return step.beginDialog(OAUTH_PROMPT);
[...]
if (step.result) {
const tokenResponse = step.result;
if (tokenResponse && tokenResponse.token) {
const parts = (step.values.command || '').toLowerCase().split(' ');
const command = parts[0];
switch (command) {
case 'me':
await OAuthHelpers.listMe(step.context, tokenResponse);
break;
case 'send':
await OAuthHelpers.sendMail(step.context, tokenResponse, parts[1]);
break;
case 'recent':
await OAuthHelpers.listRecentMail(step.context, tokenResponse);
break;
default:
await step.context.sendActivity(`Your token is ${ tokenResponse.token }`);
}
}
}
[...]
static async sendMail(context, tokenResponse, emailAddress) {
[...]
const client = new SimpleGraphClient(tokenResponse.token);
const me = await client.getMe();
await client.sendMail(
emailAddress,
'Message from a bot!',
`Hi there! I had this message sent from a bot. - Your friend, ${ me.displayName }`
);
await context.sendActivity(`I sent a message to ${ emailAddress } from your account.`);
}
这是示例的工作方式。对您来说,由于只想在Auth对话框中进行身份验证,因此需要使用Auth对话框从用户那里获取令牌,然后将其保存到其UserState中,类似于this sample。然后,您可以在任何对话框中检索其UserState并使用令牌(如果有)。