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

Python MSAL授权码流获取令牌:如何获取auth_response字典?

解决MSAL授权码流auth_response获取问题及Dynamics API认证方案

一、auth_response参数的正确获取方式

授权码流的核心逻辑是:生成授权URL → 用户登录授权 → 微软将code、state等参数通过回调URL的查询参数返回。auth_response就是这些查询参数组成的字典,分两种场景处理:

1. 基于Web框架的脚本(如Flask)

如果是Web应用,用户完成授权后,回调路由可直接提取URL查询参数转为字典:

from flask import Flask, request, redirect
import msal
import requests

app = Flask(__name__)
client_id = "你的客户端ID"
authority_url = "https://login.microsoftonline.com/你的租户ID"
scope_list = ["https://你的Dynamics地址/api/user_impersonation"]
redirect_uri = "http://localhost:5000/callback"

msal_app = msal.ClientApplication(
    client_id,
    client_credential=None,
    authority=authority_url
)

@app.route("/login")
def login():
    flow = msal_app.initiate_auth_code_flow(scopes=scope_list, redirect_uri=redirect_uri)
    # 将flow存入session,回调时复用
    app.session["flow"] = flow
    return redirect(flow["auth_uri"])

@app.route("/callback")
def callback():
    # 直接从请求中提取查询参数作为auth_response
    auth_response = request.args.to_dict()
    flow = app.session.get("flow")
    result = msal_app.acquire_token_by_auth_code_flow(flow, auth_response, scopes=scope_list)
    # 后续用result中的access_token调用Dynamics API
    return "认证完成,可关闭页面"

2. 本地桌面脚本(无Web框架)

如果是本地运行的脚本,有两种方式获取参数:

  • 临时本地服务器监听:启动小型服务器捕获回调请求的参数
import msal
import urllib.parse
from http.server import BaseHTTPRequestHandler, HTTPServer

client_id = "你的客户端ID"
authority_url = "https://login.microsoftonline.com/你的租户ID"
scope_list = ["https://你的Dynamics地址/api/user_impersonation"]
redirect_uri = "http://localhost:8888/callback"

msal_app = msal.ClientApplication(client_id, authority=authority_url)
flow = msal_app.initiate_auth_code_flow(scopes=scope_list, redirect_uri=redirect_uri)
print(f"请访问此URL完成授权:\n{flow['auth_uri']}")

class CallbackHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        # 解析URL查询参数
        query_params = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
        auth_response = {k: v[0] for k, v in query_params.items()}
        # 获取token
        result = msal_app.acquire_token_by_auth_code_flow(flow, auth_response, scopes=scope_list)
        if "access_token" in result:
            print(f"获取Token成功:\n{result['access_token']}")
        else:
            print(f"认证失败:{result.get('error_description')}")
        # 返回响应并关闭服务器
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(b"认证完成,可关闭此页面")
        server.shutdown()

server = HTTPServer(("localhost", 8888), CallbackHandler)
server.serve_forever()
  • 手动复制参数:用户完成授权后,将浏览器跳转URL中的查询参数(如?code=xxx&state=xxx)手动转为字典
# 从回调URL中复制code和state值
auth_response = {
    "code": "复制的授权码",
    "state": "复制的state值"
}
result = msal_app.acquire_token_by_auth_code_flow(session.flow, auth_response, scopes=scope_list)

二、客户端凭证流403错误排查方向

之前的403错误大概率是权限配置问题:

  • 确保Azure AD应用注册已添加Dynamics 365的应用权限(如Dynamics CRM > 应用权限 > Organization.ReadWrite.All),且完成管理员同意
  • 检查scope格式,客户端凭证流的scope应为https://你的Dynamics地址/.default(以.default结尾)
  • 确认Dynamics环境已为该Azure AD应用分配对应安全角色,无角色会被拒绝访问

三、推荐的认证方式

  • 后台服务/无人值守脚本:优先修复客户端凭证流的权限问题,该方式无需用户交互,适合自动化任务
    示例代码:
    import msal
    import requests
    
    client_id = "你的客户端ID"
    client_secret = "你的客户端密钥"
    authority_url = "https://login.microsoftonline.com/你的租户ID"
    scope = ["https://你的Dynamics地址/.default"]
    
    app = msal.ConfidentialClientApplication(
        client_id,
        client_credential=client_secret,
        authority=authority_url
    )
    result = app.acquire_token_for_client(scopes=scope)
    if "access_token" in result:
        headers = {"Authorization": f"Bearer {result['access_token']}"}
        response = requests.get("https://你的Dynamics地址/api/data/v9.2/accounts", headers=headers)
    
  • 需要用户交互的场景:继续使用授权码流,或选择设备码流(适用于无浏览器的服务器环境,用户在其他设备完成授权)
    设备码流示例:
    result = msal_app.acquire_token_by_device_flow(scopes=scope_list)
    if "user_code" in result:
        print(f"请访问{result['verification_uri']},输入代码{result['user_code']}完成授权")
        # 轮询等待用户完成操作
        while not result.get("access_token"):
            result = msal_app.acquire_token_by_device_flow(scopes=scope_list, flow=result)
    

内容的提问来源于stack exchange,提问作者ewaller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:13:14