FastAPI-Azure-Auth配置:SPA未获取自身应用注册角色问题
解决方案:让SPA应用注册控制角色与访问
核心原因
当Swagger SPA请求访问API时,Azure AD默认会在令牌中返回目标API应用注册的角色声明,而非客户端(SPA)自身的角色。要让SPA主导访问控制,需调整令牌请求逻辑与应用注册配置。
具体配置步骤
1. 修改SPA的令牌请求范围
在Swagger的OAuth2配置里,确保请求令牌的scope同时包含SPA自身的应用ID URI(格式为api://<SPA-APP-ID>/.default)和API的权限范围。示例配置如下:
scope: ["api://<API-APP-ID>/.default", "api://<SPA-APP-ID>/.default"]
这样Azure AD返回的令牌会同时携带SPA和API的角色声明,你可在SPA端提取属于自身的Role1角色来控制页面访问。
2. 调整API的权限验证逻辑
在FastAPI中,不要直接依赖API应用注册的角色,转而验证SPA传递的自身角色:
- 从请求令牌的
roles声明中,通过aud字段区分来源(SPA的aud是它自己的应用ID URI),筛选出SPA的角色 - 基于SPA角色构建访问控制依赖,示例代码:
from fastapi import Depends, HTTPException, status from fastapi_azure_auth import AzureAuthorizationCodeBearer azure_scheme = AzureAuthorizationCodeBearer( app_client_id="<SPA-APP-ID>", tenant_id="<TENANT-ID>", scopes={"api://<SPA-APP-ID>/.default": "SPA access"} ) def get_spa_roles(token: dict = Depends(azure_scheme)): spa_roles = [role for role in token.get("roles", []) if token.get("aud") == "api://<SPA-APP-ID>"] if not spa_roles: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="无有效SPA角色") return spa_roles @app.get("/protected") async def protected_route(spa_roles: list = Depends(get_spa_roles)): if "Role1" not in spa_roles: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="权限不足") return {"message": "访问通过"}
3. 清理冗余角色分配
- 确认SPA应用注册中已正确添加
Role1,且目标用户已被分配该角色 - 移除用户在API应用注册中的
Role7分配,避免令牌中出现混淆的角色声明
4. 可选:改用ID令牌获取SPA角色
若仅需SPA角色,可让Swagger请求ID令牌(ID令牌默认包含客户端应用的角色)。在OAuth2配置中设置response_type: "id_token token",同时获取ID令牌和访问令牌,从ID令牌中提取SPA角色即可。
关键注意点
aud字段是区分角色来源的核心:API角色的aud对应API应用ID URI,SPA角色的aud对应SPA应用ID URI- 若由SPA完全控制访问,无需在API应用注册中给用户分配任何角色
内容的提问来源于stack exchange,提问作者Thomas Segato
相关产品推荐
相关产品推荐

