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

基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 08:37:24