Этого можно добиться, заключив вызов API Graph и получая результат в результате процесса входа в AAD. Следующий код основан на BotBuilder-Samples 24.bot-authentication-msgraph
sample и BotFramework-WebChat 17.chat-send-history
sample с использованием React.Component.
(Обратите внимание, что образец Graph, находящийся в данный момент в главной ветке, не включает получение фотографии пользователя для входа в AAD. У меня есть PR, который добавляет эту функцию в образец, однако я также включил его здесь. I использовал образец WebChat в качестве справочного материала для построения ниже.)
WebChat
Вам понадобятся эти файлы из образца # 17, за которым следует файл App.js, который необходимо изменить:
- публичный [папка]
- favicon.ico
- index.html
- manifest.json
- src [папка]
- App.js
- index.css
- index.js
- .env
- package.json
App.js:
Примечание: я генерирую токен прямой линии локально в отдельном проекте. Предполагается, что в профиле AAD есть фотография.
import React from 'react';
import ReactWebChat, { createDirectLine, createStore} from 'botframework-webchat';
export default class extends React.Component {
constructor(props) {
super(props);
this.state = {
directLine: null,
avatarState: false, // Sets value to false; Is updated to true after login
// Sets the default styleOptions used during rendering
styleOptions: {
botAvatarImage: 'https://docs.microsoft.com/en-us/azure/bot-service/v4sdk/media/logo_bot.svg?view=azure-bot-service-4.0',
botAvatarInitials: 'BF',
userAvatarImage: 'https://github.com/compulim.png?size=64',
userAvatarInitials: 'WC'
}
};
// Creates the listener filtering for a new avatar image and applies to styleOptions
this.store = createStore(
{},
() => next => action => {
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
}
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY'
&& action.payload.activity.attachments
&& 0 in action.payload.activity.attachments
&& this.state.avatarState === false) {
let attachments = action.payload.activity.attachments;
if ('content' in attachments[0] && 'images' in attachments[0].content) {
this.setState(() => ({
styleOptions: {
userAvatarImage: attachments[0].content.images[0].contentUrl
},
avatarState: true
}));
}
}
return next(action);
}
)
}
componentDidMount() {
this.fetchToken();
}
async fetchToken() {
const res = await fetch('http://localhost:3979/directline/token', { method: 'POST' });
const { token } = await res.json();
this.setState(() => ({
directLine: createDirectLine({ token })
}));
}
render() {
return (
this.state.directLine ?
<ReactWebChat
className="chat"
directLine={ this.state.directLine }
styleOptions={ this.state.styleOptions }
store={ this.store }
{ ...this.props }
/>
:
<div>Connecting to bot…</div>
);
}
}
* * Package.json тысяча сорок-девять
{
"name": "change-avatar",
"version": "0.1.0",
"private": true,
"homepage": "",
"dependencies": {
"botframework-webchat": ">= 0.0.0-0",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"react-scripts": "2.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
MS Graph Bot
Обновите следующие файлы в образце № 24:
bot.js:
Заменить async processStep
на:
async processStep(step) {
// 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 the user is authenticated the bot can use the token to make API calls.
if (tokenResponse !== undefined) {
let parts = await this.commandState.get(step.context);
if (!parts) {
parts = step.context.activity.text;
}
const command = parts.split(' ')[0].toLowerCase();
if (command === 'me') {
await OAuthHelpers.listMe(step.context, tokenResponse);
} else if (command === 'send') {
await OAuthHelpers.sendMail(step.context, tokenResponse, parts.split(' ')[1].toLowerCase());
} else if (command === 'recent') {
await OAuthHelpers.listRecentMail(step.context, tokenResponse);
} else {
let photoResponse = await OAuthHelpers.loginData(step.context, tokenResponse);
const card = CardFactory.heroCard(
`Welcome ${ photoResponse.displayName }, you are now logged in.`,
[photoResponse],
[]
);
const reply = ({ type: ActivityTypes.Message });
reply.attachments = [card];
await step.context.sendActivity(reply);
}
} else {
// Ask the user to try logging in later as they are not logged in.
await step.context.sendActivity(`We couldn't log you in. Please try again later.`);
}
return await step.endDialog();
};
OAuth-helpers.js:
Добавить static async loginData
:
/**
* Displays information about the user in the bot.
* @param {TurnContext} turnContext A TurnContext instance containing all the data needed for processing this conversation turn.
* @param {TokenResponse} tokenResponse A response that includes a user token.
*/
static async loginData(turnContext, tokenResponse) {
if (!turnContext) {
throw new Error('OAuthHelpers.loginData(): `turnContext` cannot be undefined.');
}
if (!tokenResponse) {
throw new Error('OAuthHelpers.loginData(): `tokenResponse` cannot be undefined.');
}
try {
// Pull in the data from Microsoft Graph.
const client = new SimpleGraphClient(tokenResponse.token);
const me = await client.getMe();
const photoResponse = await client.getPhoto();
// Attaches user's profile photo to the reply activity.
if (photoResponse != null) {
let replyAttachment;
const base64 = Buffer.from(photoResponse, 'binary').toString('base64');
replyAttachment = {
contentType: 'image/jpeg',
contentUrl: `data:image/jpeg;base64,${ base64 }`
};
replyAttachment.displayName = me.displayName;
return (replyAttachment);
}
} catch (error) {
throw error;
}
}
простой граф-client.js:
Добавить async getPhoto
:
/**
* Collects the user's photo.
*/
async getPhoto() {
return await this.graphClient
.api('/me/photo/$value')
.responseType('ArrayBuffer')
.version('beta')
.get()
.then((res) => {
return res;
})
.catch((err) => {
console.log(err);
});
}
package.json:
Убедитесь, что @microsoft/microsoft-graph-client
устанавливает версию 1.0.0 из-за серьезных изменений, связанных с получением AAD 'displayName' в последующих версиях.
После того, как приведенный выше код был реализован, я смог войти в систему, после чего сразу же обновил аватар пользователя.
Надежда на помощь!