Reputation: 79
I am working on the example Bot Authentication MS GRAPH
I have desired output in the emulator channel as on the photo below:
When user joins the channel he is presented with welcome message and Login prompt. After authentication dialog is finished I want to return to the onMessageActivity
to carry on with my code. The teams channel seems not to respond to the onMembersAdded
at all.
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
foreach (var member in turnContext.Activity.MembersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
// First message and action that will happen when user joins the channel
await turnContext.SendActivityAsync(MessageFactory.Text("Welcome to Chat Bot. Please login."), cancellationToken);
// Call OAuthDialog
//await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
// await turnContext.SendActivityAsync(MessageFactory.Text($"Welcome to Audit Bot! I am happy to help!. Type 'Login' anytime to sign-in."), cancellationToken);
}
}
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext?.Activity?.Type == ActivityTypes.Invoke && turnContext.Activity.ChannelId == "msteams")
{
await turnContext.SendActivityAsync("You are using MS Teams.");
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}
else
{
await base.OnTurnAsync(turnContext, cancellationToken);
// Save any state changes that might have occured during the turn.
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}
}
protected override async Task OnTokenResponseEventAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
{
Logger.LogInformation("Running dialog with Token Response Event Activity.");
// Run the Dialog with the new Token Response Event Activity.
// Create Token globally and assigned here
token = turnContext.Activity.Value.ToString();
//var myJsonString = "{token: {Id: \"aaakkj98898983\"}}";
//var jo = JObject.Parse(token);
// cToken = jo["token"].ToString();
// await turnContext.SendActivityAsync(cToken);
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
// Call the MainDialog to display OAuth
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
// Proceed with rest of the code
Logger.LogInformation("Running dialog with Message Activity.");
// First, we use the dispatch model to determine which cognitive service(LUIS or QnA) to use.
var recognizerResult = await _botServices.Dispatch.RecognizeAsync(turnContext, cancellationToken);
// Top intent tells us which cognitive service to use. LUIS or QnA Maker
var topIntent = recognizerResult.GetTopScoringIntent();
// Next, we call the dispatcher with the top intent.
await DispatchToTopIntentAsync(turnContext, topIntent.intent, recognizerResult, cancellationToken);
}
Dialog Class ( I want to display my Graph call only once)
AddDialog(new OAuthPrompt(
nameof(OAuthPrompt),
new OAuthPromptSettings
{
ConnectionName = "my connection", // HARD CODED
Text = "Please login",
Title = "Login",
Timeout = 300000, // User has 5 minutes to login
}));
AddDialog(new TextPrompt(nameof(TextPrompt)));
// AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
{
PromptStepAsync,
LoginStepAsync
}));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
private async Task<DialogTurnResult> PromptStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var tokenResponse = (TokenResponse)stepContext.Result;
//Send token to state
// stepContext.Context.TurnState.Add("tokenResponse", tokenResponse);
if (tokenResponse != null)
{
////
await OAuthHelpers.ListMeAsync(stepContext.Context, tokenResponse);
return await stepContext.EndDialogAsync();
}
else
{
return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
}
}
private async Task<DialogTurnResult> LoginStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Get the token from the previous step. Note that we could also have gotten the
// token directly from the prompt itself. There is an example of this in the next method.
var tokenResponse = (TokenResponse)stepContext.Result;
if (tokenResponse != null)
{
await stepContext.Context.SendActivityAsync(MessageFactory.Text("You are now logged in."), cancellationToken);
// Display my name
await OAuthHelpers.ListMeAsync(stepContext.Context, tokenResponse);
// End and return to the bot onMessageActivity
return await stepContext.EndDialogAsync();
}
await stepContext.Context.SendActivityAsync(MessageFactory.Text("Login was not successful please try again."), cancellationToken);
return await stepContext.EndDialogAsync();
}
Upvotes: 1
Views: 728
Reputation: 7241
Teams will only fire the OnMembersAdded
event one time -- when the user first adds the bot. The user can delete or uninstall the bot and it will still never fire again more than just that initial time. Note: Facebook Channel is like this, too
What you want to do, instead, is to fire the OAuthPrompt
dialog on both:
OnMembersAdded
(you already do), and again inOnMessage
(need to add this here await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(OAuthPrompt)), cancellationToken);
)If the user is already authenticated, OAuthPrompt
will return the token without requesting it again. You just need to make sure that your OAuthPrompt
dialog appropriately handles users that are already authenticated. It's a good idea to have this in OnMessage
anyway, to make sure that you're always authenticated with your bot.
This can make it difficult to debug, I know. You can work around this through my answer here, which was for a similar question I answered today.
Upvotes: 1