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

使用Python通过Microsoft Graph下载用户头像并关联vCard时遇402错误求助

解决Microsoft Graph获取用户头像的HTTP 402错误及完整实现步骤

先排查HTTP 402错误的核心问题

HTTP 402通常标记为"需要付费",但在Microsoft Graph场景下,更大概率是你的令牌请求参数或配置有误:

  • 令牌请求URL错误:必须使用Azure AD标准令牌端点,格式为https://login.microsoftonline.com/{你的租户ID}/oauth2/v2.0/token
  • scope参数格式错误:需指定合法的Graph权限范围,比如获取所有用户头像需要https://graph.microsoft.com/User.Read.All
  • Content-Type错误:POST请求获取令牌时,必须设置为application/x-www-form-urlencoded
  • grant_type不匹配:使用客户端凭证流时,grant_type应为client_credentials;使用用户名密码流则为password,需根据认证方式调整
  • 许可证限制:部分用户头像功能需要对应的Office 365/Microsoft 365许可证,若租户无授权也可能触发402

完整实现步骤(获取令牌 → 拉取用户列表 → 下载头像 → 关联vCard)

以下是修正后的完整代码,包含所有关键流程:

import requests
import vobject  # 需先安装:pip install vobject
import base64

# 1. 获取Microsoft Graph访问令牌
tenant_id = "你的租户ID"
client_id = "你的客户端ID"
client_secret = "你的客户端密钥"
token_url = f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"

token_data = {
    "grant_type": "client_credentials",
    "client_id": client_id,
    "client_secret": client_secret,
    "scope": "https://graph.microsoft.com/User.Read.All"
}

token_response = requests.post(token_url, data=token_data)
token_response.raise_for_status()  # 主动抛出HTTP错误,便于调试
access_token = token_response.json()["access_token"]

# 2. 拉取租户内所有用户基础信息
request_headers = {
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json"
}
users_list_url = "https://graph.microsoft.com/v1.0/users?$select=id,displayName,mail"
users_response = requests.get(users_list_url, headers=request_headers)
users_response.raise_for_status()
users = users_response.json()["value"]

# 3. 遍历用户下载头像并完善vCard
for user in users:
    user_id = user["id"]
    display_name = user["displayName"]
    email = user.get("mail", "")
    
    # 下载用户头像(size参数可调整:48/64/120/240/480,对应不同尺寸)
    avatar_url = f"https://graph.microsoft.com/v1.0/users/{user_id}/photo/$value"
    avatar_response = requests.get(avatar_url, headers=request_headers)
    
    # 处理用户无头像的情况
    if avatar_response.status_code == 404:
        print(f"用户 {display_name} 未设置头像,跳过")
        continue
    
    avatar_response.raise_for_status()
    # 保存本地头像文件
    avatar_filename = f"{user_id}_avatar.jpg"
    with open(avatar_filename, "wb") as f:
        f.write(avatar_response.content)
    print(f"已下载用户 {display_name} 的头像:{avatar_filename}")
    
    # 4. 生成并完善vCard
    vcard = vobject.vCard()
    vcard.add("fn").value = display_name
    if email:
        vcard.add("email").value = email
        vcard.email.type_param = "INTERNET"
    
    # 将头像嵌入vCard(Base64编码)
    avatar_base64 = base64.b64encode(avatar_response.content).decode("utf-8")
    photo_field = vcard.add("photo")
    photo_field.value = avatar_base64
    photo_field.type_param = "JPEG"
    photo_field.encoding_param = "b"
    
    # 保存vCard文件
    vcard_filename = f"{user_id}.vcf"
    with open(vcard_filename, "w", encoding="utf-8") as f:
        f.write(vcard.serialize())
    print(f"已生成用户 {display_name} 的vCard:{vcard_filename}")

关键注意事项

  • 确保你的Azure AD应用已被授予User.Read.All的应用权限(而非委派权限),并完成管理员同意
  • 若使用用户名密码流(grant_type=password),需将scope改为https://graph.microsoft.com/User.Read.All offline_access,同时添加username和password参数
  • 若仍出现402错误,需检查租户是否拥有Microsoft 365商业版/企业版等包含头像功能的许可证

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 08:10:38