基于Connexion+OpenAPI3.0的Flask应用集成OAuth2与Azure AD报错求助
解决Connexion+Swagger Flask应用集成Azure AD OAuth2的跨域及PKCE错误
核心问题
你的应用是服务器端Web应用,但混淆了Azure AD中Web应用与SPA的OAuth2流程差异,导致两种配置下分别触发跨域和PKCE验证错误。
错误原因与对应解决方案
1. Web平台配置下的AADSTS9002326错误
- 原因:Web应用的授权码流程要求由后端(而非前端)使用客户端密钥兑换token,你当前的Swagger UI直接发起token兑换请求,属于跨域操作,Azure AD拒绝该行为。
- 解决:将Azure应用注册平台设为Web,并调整后端与Swagger配置,让后端处理授权码兑换逻辑。
2. SPA平台配置下的AADSTS9002325错误
- 原因:SPA类型应用的授权码流程强制要求PKCE(Proof Key for Code Exchange)验证,但你的Swagger UI或后端未实现PKCE逻辑,Azure AD因缺少必要验证信息拒绝兑换。
- 解决:放弃SPA配置,改用Web平台配置(因为你的应用是服务器端Flask应用,SPA流程不适用于此场景)。
具体实施步骤
步骤1:修正Azure AD应用注册配置
- 进入Azure门户的应用注册,将平台类型改为Web,删除SPA类型的重定向URI。
- 添加后端回调URI:
http://localhost:8004/oauth2-redirect(不要使用.html后缀,这是后端路由)。 - 在「认证」页面勾选「授权代码流」,关闭隐式流(Web应用无需隐式流)。
- 修改应用清单:
- 将
accessTokenAcceptedVersion设为2(使用Azure AD v2.0端点)。 - 确保
oauth2AllowImplicitFlow为false。
- 将
步骤2:更新Swagger配置(swagger.yml)
添加Swagger UI的OAuth2重定向配置,并确保securitySchemes正确指向Azure AD v2.0端点:
openapi: 3.0.3 info: title: 你的API名称 version: 1.0.0 components: securitySchemes: AzureAD: type: oauth2 x-tokenInfoFunc: auth.azure_ad flows: authorizationCode: authorizationUrl: "https://login.microsoftonline.com/{你的租户ID}/oauth2/v2.0/authorize" tokenUrl: "https://login.microsoftonline.com/{你的租户ID}/oauth2/v2.0/token" scopes: User.ReadBasic.All: 读取用户基本信息 Group.Read.All: 列出所有组 GroupMember.Read.All: 查看组成员 # 指定Swagger UI的前端回调地址 x-swagger-ui-oauth2-redirect-url: "http://localhost:8004/ui/oauth2-redirect.html"
步骤3:调整Flask/Connexion后端代码(app.py)
初始化Azure AD认证客户端,添加后端回调路由处理授权码兑换:
import identity.web import connexion from pathlib import Path from flask import session, redirect, url_for, request from consts import * # 创建日志目录 Path(LOG_DIR).mkdir(parents=True, exist_ok=True) app = connexion.FlaskApp(__name__, specification_dir=OPENAPI_DIR) app.add_api(OPENAPI_FILE) # 初始化Azure AD认证客户端 auth = identity.web.Auth( session=session, client_id=你的客户端ID, client_credential=你的客户端密钥, authority=f"https://login.microsoftonline.com/{你的租户ID}", redirect_uri="http://localhost:8004/oauth2-redirect", scopes=["User.ReadBasic.All", "Group.Read.All", "GroupMember.Read.All"] ) # 后端回调路由:处理授权码兑换 @app.route("/oauth2-redirect") def oauth2_redirect(): login_result = auth.complete_log_in(request.args) if "error" in login_result: return f"登录失败: {login_result['error']}", 400 # 登录成功后跳转到Swagger UI return redirect("/ui") # 登录触发路由 @app.route("/login") def login(): return redirect(auth.log_in(redirect_uri=url_for("oauth2_redirect", _external=True))) if __name__ == "__main__": app.run(host="0.0.0.0", port=8004, debug=VADER_DEBUG)
步骤4:实现token验证函数(auth.py)
确保x-tokenInfoFunc指定的auth.azure_ad函数能正确验证Azure AD颁发的access token:
import jwt import requests from consts import * def azure_ad(token): # 获取Azure AD的JWKS密钥集 jwks_url = f"https://login.microsoftonline.com/{你的租户ID}/discovery/v2.0/keys" jwks_response = requests.get(jwks_url) jwks = jwks_response.json() try: # 解析token头,匹配对应密钥 token_header = jwt.get_unverified_header(token) signing_key = next(k for k in jwks["keys"] if k["kid"] == token_header["kid"]) # 解码并验证token decoded_token = jwt.decode( token, signing_key, algorithms=["RS256"], audience=你的客户端ID, issuer=f"https://login.microsoftonline.com/{你的租户ID}/v2.0" ) return decoded_token except Exception as e: # 验证失败返回None,Connexion会拒绝请求 return None
内容的提问来源于stack exchange,提问作者Danny
相关产品推荐
相关产品推荐

