MS Teams Bot创建用户对话遇未授权错误的问题咨询
问题:Teams Bot创建用户对话时的未授权错误
我正在开发一个Azure Function应用,需要为Entra ID中的每位用户创建对话,但Bot仅安装在群组频道,执行时出现以下错误:
Error creating conversation2: Error: Error creating conversation: Unauthorized, {"message":"Authorization has been denied for this request."}
当前我使用ConfidentialClientApplication(CCA)生成的Graph Token获取用户列表并尝试创建对话,相关实现如下:
当前实现代码
1. Graph Token获取逻辑
const msalConfig = { auth: { clientId: process.env.MICROSOFT_APP_ID, clientSecret: process.env.MICROSOFT_APP_PASSWORD, authority: `https://login.microsoftonline.com/${process.env.TENANT_ID}`, } }; const cca = new ConfidentialClientApplication(msalConfig); export async function getGraphToken(): Promise<string> { try { const authResult = await cca.acquireTokenByClientCredential({ scopes: ['https://graph.microsoft.com/.default'] }); console.log('token', authResult.accessToken) return authResult.accessToken; } catch (error) { console.error("Error acquiring Graph token:", error); throw new Error("Failed to acquire Graph token"); } }
2. 定时器触发的主函数
import { app, InvocationContext, Timer } from "@azure/functions"; import { saveConversationReference, getAllUsers, CreateConversationForMSTeamsUser, addUserRefToStorage } from "../extra/conversationHandlers"; export async function createConversationInStorage2(myTimer: Timer, context: InvocationContext): Promise<void> { context.log('Timer function processed request.'); try { const users = await getAllUsers(); context.log(`Fetched ${users.length} users from Azure AD`); for (const user of users) { if (user && user.id) { context.log(`Processing user: ${user.id}`); const res = await CreateConversationForMSTeamsUser(user.id, user.displayName, user.userPrincipalName); if (res) { await addUserRefToStorage(user.id, res); } else { context.log(`Failed to create conversation for user3: ${user.id}`); } } } } catch (error) { context.log('Error retrieving users from Azure AD:', error); } } app.timer('createConversationInStorage2', { schedule: '0 */1 * * * *', handler: createConversationInStorage2 });
3. 对话创建与用户处理核心函数
import storage from './storageBlob'; import { getBotFrameworkToken, getGraphToken } from './msal'; export async function CreateConversationForMSTeamsUser(userId: string, userDisplayName: string, userPrincipalName: string) { try { const tenantId = process.env.TENANT_ID; const serviceUrl = 'https://smba.trafficmanager.net/teams/v3/conversations' const token = await getGraphToken(); const conversationParams = { members: [ { id: userId, displayName: userDisplayName, userPrincipalName: userPrincipalName }, ], isGroup: false, bot: { id: 'id here', displayName: 'app name here' } }; console.log('conversationParams', conversationParams) const conversationResponse = await fetch( serviceUrl, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, body: JSON.stringify(conversationParams), } ); console.log('conversationResponse', conversationResponse) if (!conversationResponse.ok) { const errorText = await conversationResponse.text(); throw new Error(`Error creating conversation: ${conversationResponse.statusText}, ${errorText}`); } const conversation = await conversationResponse.json(); console.log('conversation', conversation) return conversation; } catch (error) { console.error('Error creating conversation2:', error); return null; } } export async function saveConversationReference(userId: string, conversationId: string) { const reference = { user: { id: userId }, conversation: { id: conversationId } }; try { const res = await storage.add(userId, reference, { overwrite: true }); console.log(`Conversation reference saved for user ${userId}:`, res); } catch (error) { console.error(`Error saving conversation reference for user ${userId}:`, error); } } export async function getAllUsers(): Promise<any[]> { const token = await getGraphToken(); const usersResponse = await fetch("https://graph.microsoft.com/v1.0/users", { headers: { Authorization: `Bearer ${token}` }, }); if (!usersResponse.ok) { throw new Error(`Error fetching users: ${usersResponse.statusText}`); } const usersJson = await usersResponse.json(); if (!usersJson.value || !Array.isArray(usersJson.value)) { throw new TypeError('Expected an array of users in the response'); } return usersJson.value; } export async function addUserRefToStorage(userId: string, conversationRef: any) { try { if (!conversationRef) { throw new Error('Invalid conversation reference'); } const res = await storage.add(userId, conversationRef, { overwrite: true }); console.log(`User ID saved for user ${userId}:`, res); } catch (error) { console.error(`Error saving user conversation reference for ${userId}:`, error); } }
4. Bot Framework Token尝试代码
我猜测可能需要使用Bot Framework Token而非Graph Token,相关获取代码如下:
try { const authResult = await cca.acquireTokenByClientCredential({ scopes: ['https://api.botframework.com/.default'] // scopes: ['https://smba.trafficmanager.net/.default'] }); console.log('authResult', authResult.accessToken); return authResult.accessToken; } catch (error) { console.error("Error acquiring Bot Framework token:", error); throw new Error("Failed to acquire Bot Framework token"); }
疑问与需求
- 若使用Bot Framework Token端点,如何配置创建聊天及读写权限?(已为Graph Token配置过相关权限)
- 如何解决未授权错误,实现为每位用户创建对话?
内容的提问来源于stack exchange,提问作者Justin J
相关产品推荐
相关产品推荐

