从Azure凭证获取用户ID/邮箱:适配用户账户与服务主体
问题:适配各类Azure客户端、可获取UPN/OID的正确Scope是什么?
我们基于Azure ML与Python搭建开发环境,使用azure-identity库的DefaultAzureCredential进行授权,该凭证可匹配CLI或VSCode的登录凭证。希望通过代码获取当前用户的邮箱地址(UPN)或ID(OID),初始代码如下:
from azure.identity import DefaultAzureCredential credential = DefaultAzureCredential() token = credential.get_token("https://management.azure.com/", scopes=["user.read"]) current_user_id = ???
后续尝试解析token获取用户信息,更新后的代码如下:
import json import base64 from azure.identity import DefaultAzureCredential credential = DefaultAzureCredential() token = credential.get_token("https://management.azure.com/", scopes=["user.read"]) base64_meta_data = token.token.split(".")[1].encode("utf-8") + b'==' json_bytes = base64.decodebytes(base64_meta_data) json_string = json_bytes.decode("utf-8") json_dict = json.loads(json_string) current_user_id = json_dict["upn"] print(f"{current_user_id=}")
但该方法对服务主体无效,获取token时触发报错:
DefaultAzureCredential failed to retrieve a token from the included credentials. Attempted credentials: EnvironmentCredential: Authentication failed: ClientApplication.acquire_token_silent_with_error() got multiple values for argument 'scopes'
请问适配各类客户端、可获取UPN/OID的合适Scope是什么?
解决方案
核心问题分析
- 参数调用错误:
get_token方法的第一个参数就是scope,无需额外传递resource参数(如https://management.azure.com/),重复传参导致服务主体身份验证报错。 - 身份类型差异:用户身份有UPN(邮箱),但服务主体身份没有UPN字段,只有OID(对象ID),需要区分处理。
正确的Scope选择
获取身份信息优先使用Microsoft Graph的scope,而非Azure Management的scope,因为Graph专门用于身份和资源查询:
- 对于用户身份:
https://graph.microsoft.com/user.read(仅获取用户基本信息) - 对于服务主体:
https://graph.microsoft.com/.default(使用服务主体的默认权限,需提前配置Graph权限) - 通用兼容的scope:
https://graph.microsoft.com/.default,可同时适配用户和服务主体身份。
修正后的代码
import json import base64 from azure.identity import DefaultAzureCredential credential = DefaultAzureCredential() # 使用正确的scope参数,无需传resource token = credential.get_token("https://graph.microsoft.com/.default") # 解析JWT Token的Payload部分 try: payload_base64 = token.token.split(".")[1] # Base64填充处理 payload_base64 += "=" * ((4 - len(payload_base64) % 4) % 4) payload_bytes = base64.urlsafe_b64decode(payload_base64) payload = json.loads(payload_bytes) # 区分用户和服务主体 if "upn" in payload: current_identity = payload["upn"] identity_type = "用户邮箱(UPN)" elif "oid" in payload: current_identity = payload["oid"] identity_type = "服务主体ID(OID)" else: current_identity = "无法识别的身份类型" identity_type = "未知" print(f"当前身份类型:{identity_type},值:{current_identity}") except Exception as e: print(f"解析身份信息失败:{str(e)}")
关键说明
get_token方法仅需传入scope字符串(或列表),之前的https://management.azure.com/是冗余参数,会导致服务主体身份验证时参数冲突。- 服务主体的JWT Token中没有
upn字段,只能通过oid获取其唯一ID。 - 使用
https://graph.microsoft.com/.default时,服务主体需在Azure AD中配置对应的Microsoft Graph权限(如Directory.Read.All),否则可能会触发权限不足的错误。
内容的提问来源于stack exchange,提问作者casparjespersen
相关产品推荐
相关产品推荐

