FastAPI集成Azure EntraID认证调用API遇scope问题,求解决方案
问题分析与解决方案
你的核心问题在于客户端凭证(client_credentials)模式下,Azure Entra ID 不支持直接指定自定义委派权限 scope,且该模式生成的令牌中,应用权限会放在roles声明而非scope声明里,导致原API的validate_scope验证逻辑失效。以下是具体解决步骤:
一、修正Azure Entra ID应用配置
- 进入Azure Portal的Entra ID控制台,找到你的API应用注册
- 切换到API权限页面,点击「添加权限」→「我的API」,选择当前API应用
- 选择应用权限(而非委派权限,因为client_credentials是无用户的服务间调用模式),添加名为
access_api的权限(与你代码中的scope值一致) - 点击「授予管理员同意」(必须完成此步骤,否则客户端无法获取权限)
二、修改API验证逻辑
原代码的validate_scope是针对委派权限的验证逻辑,不适用于客户端凭证模式的应用权限。需替换为角色验证:
from fastapi import APIRouter,Request from fastapi_microsoft_identity import AuthError,requires_auth,validate_roles import fastapi from fastapi.exceptions import HTTPException from pydantic import ValidationError from utills.config import AppConfigs poc_router = APIRouter() required_role = "access_api" @poc_router.get("/add/{num1}/{num2}") @requires_auth async def add_with_auth(request:Request,num1:int,num2:int): try: # 替换validate_scope为validate_roles,验证应用权限 validate_roles(required_roles=[required_role], request=request) return num1+num2 except AuthError as ae: return fastapi.Response(content=ae.error_msg, status_code=ae.status_code) except ValidationError as ve: return fastapi.Response(content=str(ve), status_code=400) except Exception as e: raise HTTPException(status_code=403,detail=f"Failed with Exception--{str(e)}")
三、保留令牌获取代码(无需修改)
客户端凭证模式下,必须使用api://{CLIENT_ID}/.default作为scope,它会自动包含所有已授予该客户端的应用权限。你的令牌获取代码是正确的:
from utills.config import AppConfigs import subprocess,json def get_ad_token(): curl_cmd = [ "curl", "-X","post", f"https://login.microsoftonline.com/{AppConfigs.TENANT_ID}/oauth2/v2.0/token", "-d", "grant_type=client_credentials", "-d", f"client_id={AppConfigs.CLIENT_ID}", "-d", f"client_secret={AppConfigs.CLIENT_SECRET}", "-d", f"scope=api://{AppConfigs.CLIENT_ID}/.default" ] res=subprocess.run(curl_cmd,capture_output=True,text=True) access_token = json.loads(res.stdout) return access_token["access_token"]
关键说明
- 客户端凭证模式(client_credentials)是服务到服务的调用模式,无用户参与,因此只能使用应用权限(对应令牌中的
roles声明),不能使用委派权限(对应scope声明) /.default是该模式下的特殊scope,代表客户端被授予的所有应用权限的集合,无法替换为单个自定义scope
内容的提问来源于stack exchange,提问作者Mohammed Sohail
相关产品推荐
相关产品推荐

