You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Microsoft Graph API 401未授权错误:Teams消息发送限制问题

Microsoft Graph API发送团队频道回复报错401的解决方案

问题场景

使用Client Credential Flow(仅应用权限上下文)调用Microsoft Graph API发送Teams频道消息回复时,返回401错误,提示仅导入场景允许该操作。

已配置的API权限

  • ChannelMessage.Read.All(Application类型)
  • ChannelMessage.ReadWrite(Delegated类型)
  • ChannelMessage.Send(Delegated类型)
  • Chat.ReadWrite.All(Application类型)
  • Group.ReadWrite.All(Application类型)
  • Teamwork.Migrate.All(Application类型)
  • User.Read(Delegated类型)

代码实现

import msal
import constants
import requests

def generate_access_token(app_id, client_secret, authority, scopes):
    # 创建带客户端凭据的ConfidentialClientApplication
    client = msal.ConfidentialClientApplication(
        client_id=app_id,
        client_credential=client_secret,
        authority=authority
    )
    # 通过客户端凭据获取令牌
    token_response = client.acquire_token_for_client(scopes=scopes)
    if 'access_token' in token_response:
        return token_response['access_token']
    else:
        print("获取令牌失败:", token_response.get("error_description"))
        return None

def test_post_message_to_channel( app_id, client_secret, authority, scopes, team_id, channel_id, message_content):
    access_token = generate_access_token(app_id, client_secret, authority, scopes)
    url = f"https://graph.microsoft.com/v1.0/teams/{team_id}/channels/{channel_id}/messages"
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    payload = {
        "body": {
            "content": message_content
        }
    }
    
    response = requests.post(url, headers=headers, json=payload)
    
    if response.status_code == 201:
        print("消息发送成功!")
        return response.json()
    else:
        print("消息发送失败:", response.status_code, response.text)
        return None

def test_reply_message_to_channel(app_id, client_secret, authority, scopes, team_id, channel_id, message_id, reply_content):
    # 获取访问令牌
    access_token = generate_access_token(app_id, client_secret, authority, scopes)
    
    # 定义API端点和回复内容
    url = f'https://graph.microsoft.com/v1.0/teams/{team_id}/channels/{channel_id}/messages/{message_id}/replies'
    headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }
    payload = {
        "body": {
            "content": reply_content
        }
    }

    # 发送回复
    response = requests.post(url, headers=headers, json=payload)

    # 检查回复状态
    if response.status_code == 201:
        print("回复发送成功!")
    else:
        print("回复发送失败:", response.status_code, response.text)

# 调用示例
if __name__ == "__main__":
    test_reply_message_to_channel( 
        app_id=constants.APP_ID, 
        client_secret=constants.CLIENT_SECRET, 
        authority=constants.AUTHORITY, 
        scopes=constants.SCOPES, 
        team_id=constants.TEAM_ID, 
        channel_id=constants.CHANNEL_ID, 
        message_id=constants.MESSAGE_ID,
        reply_content=constants.MESSAGE_CONTENT
    )

错误详情

{
    "error": {
        "code": "Unauthorized",
        "message": "仅导入场景允许在仅应用权限上下文下发送消息。",
        "innerError": {
            "date": "2024-11-26T12:10:19",
            "request-id": "da3b9b53-43d3-407a-9608-9797217e4909",
            "client-request-id": "da3b9b53-43d3-407a-9608-9797217e4909"
        }
    }
}

无需用户登录的替代方案

方案1:走消息导入流程

利用已配置的Teamwork.Migrate.All应用权限,按照导入历史消息的规则发送回复:

  1. 在请求头中添加Importance: high
  2. 请求体必须指定createdDateTime(需设置为过去的时间)和from字段(模拟具体用户发送)
  3. 修改后的请求示例:
headers = {
    'Authorization': f'Bearer {access_token}',
    'Content-Type': 'application/json',
    'Importance': 'high'
}
payload = {
    "body": {
        "content": reply_content
    },
    "createdDateTime": "2024-11-25T10:00:00Z",
    "from": {
        "user": {
            "id": "<目标用户ID>",
            "displayName": "<用户显示名称>"
        }
    }
}

该方式发送的消息会被标记为外部导入的历史消息,适合数据迁移场景。

方案2:使用On-Behalf-Of (OBO) 流程

让应用代表指定用户发送实时消息,无需用户手动登录:

  1. 确保应用已获得ChannelMessage.Send(Delegated类型)权限,且管理员已同意该权限
  2. 通过前端或其他渠道获取用户授权码,后端使用OBO流程将授权码转换为代表用户的访问令牌
  3. 用该令牌调用发送消息API,即可模拟用户发送实时消息

方案3:注册Teams机器人

通过Teams机器人身份发送消息:

  1. 在Azure中注册Teams机器人应用,配置权限时添加ChannelMessage.Send
  2. 使用机器人的访问令牌调用Graph API发送消息或回复
  3. 机器人可直接以应用身份在频道发送消息,无需关联具体用户,适合实时通知类场景

内容的提问来源于stack exchange,提问作者Emmanuel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 22:30:05