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
相关产品推荐
相关产品推荐

