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

如何基于Azure AD实现REST API的程序化访问授权(替代基础认证)

针对Python脚本程序化调用API的Azure AD认证方案

核心可选方案

根据你的场景(禁止资源所有者密码流,需替代基础认证),有两个符合安全最佳实践的方案可选:

方案1:授权码流 + PKCE(适合需代表特定用户调用的脚本)

授权码流+PKCE并非只能用于前端跳转,针对Python脚本可以实现一次性交互授权+后续静默刷新的模式:

  1. Azure AD应用配置

    • 注册一个公共客户端应用(控制台/桌面应用类型,无需客户端密钥)
    • 为该应用添加目标API的委托权限(若脚本需要用户上下文),并确保权限已获得管理员同意
    • 设置重定向URI为http://localhost:8000(用于本地回调)
  2. 脚本实现逻辑

    • 首次运行时,自动打开浏览器引导用户完成Azure AD登录,获取授权码
    • 用授权码+PKCE参数交换访问令牌和刷新令牌,将刷新令牌本地持久化(比如写入文件)
    • 后续脚本运行时,直接读取刷新令牌静默获取新的访问令牌,无需用户交互

    Python示例(依赖msal库):

    import msal
    import webbrowser
    import os
    
    # 配置项
    CLIENT_ID = "你的公共客户端应用ID"
    TENANT_ID = "你的Azure AD租户ID"
    API_SCOPE = ["api://你的API应用ID/你的权限范围"]  # 例如 ["api://xxxx/user.read"]
    REFRESH_TOKEN_FILE = "refresh_token.txt"
    
    # 初始化MSAL客户端
    app = msal.PublicClientApplication(CLIENT_ID, authority=f"https://login.microsoftonline.com/{TENANT_ID}")
    
    # 尝试从缓存或本地文件获取刷新令牌
    result = app.acquire_token_silent(API_SCOPE, account=None)
    if not result and os.path.exists(REFRESH_TOKEN_FILE):
        with open(REFRESH_TOKEN_FILE, "r") as f:
            refresh_token = f.read().strip()
            result = app.acquire_token_by_refresh_token(refresh_token, API_SCOPE)
    
    if not result:
        # 首次授权:发起PKCE流程,打开浏览器
        flow = app.initiate_auth_code_flow(API_SCOPE, redirect_uri="http://localhost:8000")
        webbrowser.open(flow["auth_uri"])
        # 手动输入授权码(或用本地HTTP服务器自动捕获回调)
        auth_code = input("请复制浏览器地址栏中的授权码并输入:")
        result = app.acquire_token_by_auth_code_flow(flow, auth_code)
    
        # 保存刷新令牌到本地
        if "refresh_token" in result:
            with open(REFRESH_TOKEN_FILE, "w") as f:
                f.write(result["refresh_token"])
    
    if "access_token" in result:
        # 用访问令牌调用API
        print(f"获取访问令牌成功,有效期:{result['expires_in']}秒")
        # 示例:requests.get("你的API地址", headers={"Authorization": f"Bearer {result['access_token']}"})
    else:
        print(f"令牌获取失败:{result.get('error_description', result.get('error'))}")
    

方案2:客户端凭证流(适合无用户上下文的服务间调用)

如果脚本不需要模拟特定用户,而是以服务身份独立调用API,客户端凭证流是更合适的选择:

  1. Azure AD应用配置

    • 注册一个机密客户端应用,生成客户端密钥(或使用证书提升安全性)
    • 为该应用添加目标API的应用权限(而非委托权限),并完成管理员同意
    • 确保API应用已将权限范围暴露给客户端应用
  2. 脚本实现逻辑

    • 直接用客户端ID+密钥(或证书)向Azure AD请求访问令牌,全程无用户交互

    Python示例:

    import msal
    
    # 配置项
    CLIENT_ID = "你的机密客户端应用ID"
    CLIENT_SECRET = "你的客户端密钥"
    TENANT_ID = "你的Azure AD租户ID"
    API_SCOPE = ["api://你的API应用ID/.default"]  # .default代表应用权限的默认范围
    
    # 初始化MSAL客户端
    app = msal.ConfidentialClientApplication(
        CLIENT_ID,
        authority=f"https://login.microsoftonline.com/{TENANT_ID}",
        client_credential=CLIENT_SECRET
    )
    
    # 获取服务身份令牌
    result = app.acquire_token_for_client(scopes=API_SCOPE)
    
    if "access_token" in result:
        print(f"服务身份令牌获取成功:{result['access_token']}")
        # 调用API:requests.get("你的API地址", headers={"Authorization": f"Bearer {result['access_token']}"})
    else:
        print(f"令牌获取失败:{result.get('error_description', result.get('error'))}")
    

API端的授权适配

不管用哪种方案,API端需要做以下配置来替代原有的LDAP+AD组授权:

  • 在Azure AD注册API应用,定义权限范围(scopes)或应用角色(roles)
  • 将原AD全局组映射到Azure AD的组或应用角色,在令牌中通过groups或roles声明传递
  • 在API的认证中间件中验证Azure AD颁发的JWT令牌,检查声明中的权限/组信息完成授权

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:38:13