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

msgraph-sdk-python无法返回用户数据问题求助

问题:获取Access Token正常但无法返回用户列表

按照微软官方教程实现Python应用权限调用Graph API,成功获取App-Only模式的Access Token,但执行列表用户操作时无结果返回,仅打印None。

main.py 文件

import asyncio
import configparser
from msgraph.generated.models.o_data_errors.o_data_error import ODataError
from graph import Graph

async def main():
    print('Python Graph App-Only Tutorial\n')

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

    graph: Graph = Graph(azure_settings)

    choice = -1

    while choice != 0:
        print('Please choose one of the following options:')
        print('0. Exit')
        print('1. Display access token')
        print('2. List users')
        print('3. Me')

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

        try:
            if choice == 0:
                print('Goodbye...')
            elif choice == 1:
                await display_access_token(graph)
            elif choice == 2:
                await list_users(graph)
            elif choice == 3:
                await mee(graph)
            else:
                print('Invalid choice!\n')
        except ODataError as odata_error:
            print('Error:')
            if odata_error.error:
                print(odata_error.error.code, odata_error.error.message)

async def display_access_token(graph: Graph):
    token = await graph.get_app_only_token()
    print('App-only token:', token, '\n')

async def list_users(graph: Graph):
    users_page = await graph.get_users()
    print(users_page)

    # Output each users's details
    if users_page and users_page.value:
        for user in users_page.value:
            print('User:', user.display_name)
            print('  ID:', user.id)
            print('  Email:', user.mail)

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


async def mee(graph: Graph):
    user = await graph.me()

async def make_graph_call(graph: Graph):
    # TODO
    return

# Run main
asyncio.run(main())

graph.py 文件

from configparser import SectionProxy
from azure.identity.aio import ClientSecretCredential
from kiota_authentication_azure.azure_identity_authentication_provider import (
    AzureIdentityAuthenticationProvider
)
from msgraph import GraphRequestAdapter, GraphServiceClient
from msgraph.generated.users.users_request_builder import UsersRequestBuilder
from kiota_abstractions.api_error import APIError
import asyncio
class Graph:
    settings: SectionProxy
    client_credential: ClientSecretCredential
    adapter: GraphRequestAdapter
    app_client: GraphServiceClient

    def __init__(self, config: SectionProxy):
        self.settings = config
        client_id = self.settings['clientId']
        tenant_id = self.settings['tenantId']
        client_secret = self.settings['clientSecret']

        self.client_credential = ClientSecretCredential(tenant_id, client_id, client_secret)
        auth_provider = AzureIdentityAuthenticationProvider(self.client_credential) # type: ignore
        self.adapter = GraphRequestAdapter(auth_provider)
        self.app_client = GraphServiceClient(self.adapter)

    async def get_app_only_token(self):
        graph_scope = 'https://graph.microsoft.com/.default'
        access_token = await self.client_credential.get_token(graph_scope)
        return access_token.token
    
    async def get_users(self):
        try:
            query_params = UsersRequestBuilder.UsersRequestBuilderGetQueryParameters(
                # Only request specific properties
                select = ['displayName', 'id', 'mail'],
                # Get at most 25 results
                top = 25,
                # Sort by display name
                orderby= ['displayName']
            )
            request_config = UsersRequestBuilder.UsersRequestBuilderGetRequestConfiguration(
                query_parameters=query_params
            )

            users = await self.app_client.users.get(request_configuration=request_config)
            return users
        except APIError as e:
            print(f'Error: {e.error.message}')
            

    async def me(self):
        try:
            me = await self.app_client.me.get()
            if me:
                print(me)
        except APIError as e:
            print(f'Error: {e}')

输出情况

选择选项2后,控制台仅输出None,无任何用户信息。


问题分析与解决方案

1. 核心问题:应用权限缺失

App-Only模式下调用/users接口需要User.Read.All(或更高权限)的应用权限,且必须完成管理员同意。如果未配置该权限,Graph API会返回权限不足错误,但当前代码未抛出该错误,导致返回None。

2. 修复步骤

步骤1:配置应用权限
  • 登录Azure门户,进入Azure Active Directory → 应用注册,找到你的应用。
  • 切换到API权限页面,点击添加权限 → 选择Microsoft Graph → 选择应用权限。
  • 搜索并添加User.Read.All权限,然后点击授予管理员同意(需要全局管理员权限)。
步骤2:修复错误处理逻辑

修改graph.py中的get_users方法,捕获错误后抛出,让上层代码处理:

async def get_users(self):
    try:
        query_params = UsersRequestBuilder.UsersRequestBuilderGetQueryParameters(
            select = ['displayName', 'id', 'mail'],
            top = 25,
            orderby= ['displayName']
        )
        request_config = UsersRequestBuilder.UsersRequestBuilderGetRequestConfiguration(
            query_parameters=query_params
        )

        users = await self.app_client.users.get(request_configuration=request_config)
        return users
    except APIError as e:
        print(f'请求Graph API错误: {e.error.message}')
        raise  # 抛出错误,让上层的ODataError捕获逻辑处理
步骤3:移除无效的/me调用

App-Only模式没有当前用户上下文,调用/me接口会报错,修改main.py中的mee函数:

async def mee(graph: Graph):
    print("App-Only模式下无法调用/me接口,请使用用户ID查询具体用户信息。")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:37:14