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

Python对接Microsoft Graph API遇授权码获取失败及代码报错求助

问题描述

我在华盛顿特区的实习项目中,用Python和Microsoft Graph API开发程序,用来检查公司员工邮箱是否新增了其他授权方式——一旦检测到新增,可能意味着有恶意人员试图访问信息。我参考了Jie Jenn的视频《Getting Started With Microsoft Graph API For Python Development (Set Up & Authentication)》,现在程序能生成设备代码和链接,但无法获取授权码。另外还遇到两个报错:

  • demo2.py第31行:TypeError: 'dict' object is not callable
  • main.py第12行和第100行:TypeError: Graph() takes no arguments

错误详情

demo2.py报错

Traceback (most recent call last):
File "C:\Users\S.Soundararajan\Documents\PE Project for Azure\demo2.py", line 31, in 
webbrowser.open(flow('verification_uri'))
TypeError: 'dict' object is not callable

main.py报错

Traceback (most recent call last):
File "C:\Users\S.Soundararajan\Documents\PE Project for Azure\main.py", line 100, in 
main()
File "C:\Users\S.Soundararajan\Documents\PE Project for Azure\main.py", line 12, in main
graph: Graph = Graph(azure_settings)
TypeError: Graph() takes no arguments
Python Graph Tutorial

相关代码

demo2.py

#import account as account
import webbrowser 
from xmlrpc.client import APPLICATION_ERROR
import requests
import msal
from msal import PublicClientApplication

CLIENT_ID = ''
CLIENT_SECRET = ''
authority_url = ''
base_url = 'https://graph.microsoft.com/v1.0/'

endpoint = base_url + 'me'
SCOPES = ['User.Read', 'Mail.Read', 'Mail.Send']

# Method 2. Login to acquire access_token
app = PublicClientApplication(
    CLIENT_ID,
    authority = authority_url
)

#accounts = app.get_accounts()
#if accounts:
    #app.acquire_token_silent(scopes=SCOPES, account=account[0])

flow = app.initiate_device_flow(scopes=SCOPES)
print(flow)
print(flow['message'])
#app_code = flow['message']
webbrowser.open(flow('verification_uri'))

result = app.acquire_token_by_device_flow(flow)
access_token_id = result['access_token']
headers = {'Authorization': 'Bearer' + access_token_id}


response = requests.get(endpoint, headers=headers)
print(response)
print(response.json())

main.py

import configparser
from graph import Graph
from msal import PublicClientApplication
def main():
    print('Python Graph Tutorial\n')

    # Load settings
    config = configparser.ConfigParser()
    config.read(['config.cfg', 'config.dev.cfg'])
    azure_settings = config['azure']

    graph: Graph = Graph(azure_settings)

    greet_user(graph)

    choice = -1

    while choice != 0:
        print('Please choose one of the following options:')
        print('0. Exit')
        print('1. Display access token')
        print('2. List my inbox')
        print('3. Send mail')
        print('4. List users (requires app-only)')
        print('5. Make a Graph call')

        try:
            choice = int(input())
        except ValueError:
            choice = -1

        if choice == 0:
            print('Goodbye...')
        elif choice == 1:
            display_access_token(graph)
        elif choice == 2:
            list_inbox(graph)
        elif choice == 3:
            send_mail(graph)
        elif choice == 4:
            list_users(graph)
        elif choice == 5:
            make_graph_call(graph)
        else:
            print('Invalid choice!\n')

def greet_user(graph: Graph):
    user = graph.get_user()
    print('Hello,', user['displayName'])
    # For Work/school accounts, email is in mail property
    # Personal accounts, email is in userPrincipalName
    print('Email:', user['mail'] or user['userPrincipalName'], '\n')

def display_access_token(graph: Graph):
    token = graph.get_user_token()
    print('User token:', token, '\n')
    return 1

def list_users(graph: Graph):
    users_page = graph.get_users()

    # Output each users's details
        for user in users_page['value']:
            print('User:', user['displayName'])
            print('  ID:', user['id'])
            print('  Email:', user['mail'])

    # If @odata.nextLink is present
    more_available = '@odata.nextLink' in users_page
    print('\nMore users available?', more_available, '\n')

def list_inbox(graph: Graph):
        message_page = graph.get_inbox()

        # Output each message's details
        for message in message_page['value']:
            print('Message:', message['subject'])
            print('  From:', message['from']['emailAddress']['name'])
            print('  Status:', 'Read' if message['isRead'] else 'Unread')
            print('  Received:', message['receivedDateTime'])

        # If @odata.nextLink is present
        more_available = '@odata.nextLink' in message_page
        print('\nMore messages available?', more_available, '\n')


def send_mail(graph: Graph):
    # Send mail to the signed-in user
    # Get the user for their email address
    user = graph.get_user()
    user_email = user['mail'] or user['userPrincipalName']

    graph.send_mail('Testing Microsoft Graph', 'Hello world!', user_email)
    print('Mail sent.\n')

def make_graph_call(graph: Graph):
    graph.make_graph_call()

# Run main
main()

解决方案

1. 修复demo2.py的dict is not callable错误

app.initiate_device_flow()返回的是字典类型,你误用了函数调用语法flow('verification_uri'),正确写法是字典取值的flow['verification_uri']。修改第31行:

webbrowser.open(flow['verification_uri'])

额外建议:在调用acquire_token_by_device_flow前先检查设备流是否初始化成功,避免后续报错:

if 'error' in flow:
    print(f"设备流初始化失败: {flow['error']}")
    exit()

2. 修复main.py的Graph() takes no arguments错误

该错误说明你导入的Graph类没有定义接收参数的构造方法。需要修改graph.py中的Graph类,添加__init__方法来接收azure_settings参数,示例如下:

class Graph:
    def __init__(self, azure_settings):
        self.settings = azure_settings
        # 在这里初始化MSAL客户端或其他需要的资源

    # 保留get_user、get_inbox等原有方法的实现逻辑

如果是参考教程中的Graph类,请确保它的构造方法支持传入配置参数,或者检查你是否正确实现了该类。

3. 其他需要修正的问题

  • device flow属于公共客户端认证,不需要CLIENT_SECRET,可以移除demo2.py中的该变量。
  • 请求头中Bearer和token之间需要加空格,否则会导致授权失败:headers={'Authorization': f'Bearer {access_token_id}'}
  • main.py中list_users和list_inbox函数内的for循环存在缩进错误,需要调整缩进对齐,否则会触发语法报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 12:40:43