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

如何在Python/Flask Web应用中通过Azure App Service Auth基于用户权限访问Blob

问题核心分析

你当前的问题是:使用App Service系统托管身份调用Blob存储时,所有操作都以应用身份执行,而非登录用户的身份,导致无法基于用户权限控制容器访问和Blob上传。核心解决思路是获取登录用户的Azure AD访问令牌,用该令牌作为凭据调用Blob存储API,而非依赖托管身份。

以下是具体实现方案:

方案1:利用App Service Easy Auth(已启用的身份验证组件)获取用户令牌

这是最适合你现有场景的方案,无需额外引入复杂的身份验证库,直接复用App Service自带的Easy Auth能力:

步骤说明

  1. 确认Easy Auth配置:确保已限制企业用户登录,且在身份验证设置中,将「允许的令牌受众」添加为Blob存储的资源ID:https://storage.azure.com(确保返回的访问令牌可用于Blob存储API)。
  2. 获取用户访问令牌:用户登录后,Easy Auth会自动在请求头注入X-MS-TOKEN-AAD-ACCESS-TOKEN;也可通过请求/.auth/me端点解析用户身份信息及令牌。
  3. 用用户令牌构建BlobServiceClient:以用户令牌为凭据创建客户端,此时所有Blob操作都会遵循该用户的RBAC权限。

Flask代码示例

from flask import request
from azure.storage.blob import BlobServiceClient

# 初始化Flask应用(省略已有代码)

def get_user_blob_client():
    # 从请求头获取用户的AAD访问令牌
    user_token = request.headers.get("X-MS-TOKEN-AAD-ACCESS-TOKEN")
    if not user_token:
        return None
    
    # 用用户令牌创建BlobServiceClient
    return BlobServiceClient(
        account_url="https://<你的存储账户名>.blob.core.windows.net",
        credential=user_token
    )

# 示例:列出用户有权限访问的容器
@app.route("/containers")
def list_user_containers():
    blob_client = get_user_blob_client()
    if not blob_client:
        return "未授权", 401
    
    containers = blob_client.list_containers()
    return [container.name for container in containers]

# 示例:上传Blob到用户有权限的容器
@app.route("/upload/<container_name>", methods=["POST"])
def upload_blob(container_name):
    blob_client = get_user_blob_client()
    if not blob_client:
        return "未授权", 401
    
    blob_container_client = blob_client.get_container_client(container_name)
    # 从请求中获取文件对象(需根据你的前端上传逻辑调整)
    file = request.files["file"]
    blob_container_client.upload_blob(name=file.filename, data=file)
    return "上传成功", 200

方案2:用MSAL Python库自定义身份验证流程

如果需要更灵活的登录控制(比如自定义登录页面、令牌刷新逻辑),可直接集成MSAL库:

步骤说明

  1. 注册AAD客户端应用:在Azure AD中注册应用,配置重定向URI(例如https://<你的App Service域名>/authorized),添加「Azure Storage」的user_impersonation委托权限,并完成管理员同意。
  2. 集成MSAL实现登录流程:在Flask中实现登录跳转、令牌获取逻辑。
  3. 用用户令牌调用Blob存储:获取用户令牌后,以其为凭据构建BlobServiceClient。

Flask代码示例

import msal
from flask import Flask, redirect, request, session, url_for

app = Flask(__name__)
app.secret_key = "你的Flask密钥"

# MSAL配置
CLIENT_ID = "<你的AAD客户端ID>"
CLIENT_SECRET = "<你的AAD客户端密钥>"
AUTHORITY = "https://login.microsoftonline.com/<你的租户ID>"
# Blob存储的权限范围
SCOPE = ["https://storage.azure.com/.default"]

@app.route("/login")
def login():
    msal_client = msal.ConfidentialClientApplication(
        CLIENT_ID, authority=AUTHORITY, client_credential=CLIENT_SECRET
    )
    # 生成授权URL
    auth_url = msal_client.get_authorization_request_url(
        SCOPE, redirect_uri=url_for("authorized", _external=True)
    )
    return redirect(auth_url)

@app.route("/authorized")
def authorized():
    code = request.args.get("code")
    msal_client = msal.ConfidentialClientApplication(
        CLIENT_ID, authority=AUTHORITY, client_credential=CLIENT_SECRET
    )
    # 通过授权码获取用户令牌
    result = msal_client.acquire_token_by_authorization_code(
        code, SCOPE, redirect_uri=url_for("authorized", _external=True)
    )
    if "access_token" in result:
        session["user_token"] = result["access_token"]
        return redirect("/containers")
    return "登录失败", 401

@app.route("/containers")
def list_containers():
    user_token = session.get("user_token")
    if not user_token:
        return redirect("/login")
    
    blob_client = BlobServiceClient(
        account_url="https://<你的存储账户名>.blob.core.windows.net",
        credential=user_token
    )
    containers = blob_client.list_containers()
    return [container.name for container in containers]

关于「双应用注册+user_impersonation」的逻辑解释

这个方案主要用于自定义API场景,而非Blob存储这类微软原生服务:

  • 「资源应用」:代表你的自定义后端API,需定义user_impersonation权限(允许客户端应用以用户身份访问该API)。
  • 「客户端应用」:你的Flask应用,需申请访问资源应用的user_impersonation权限。
  • 流程:用户登录客户端应用后,客户端获取带有user_impersonation权限的令牌,用该令牌调用资源API,此时资源API会识别用户身份并控制权限。

对于Blob存储,微软已提供现成的资源应用(https://storage.azure.com),无需额外注册资源应用,直接使用其user_impersonation权限即可,也就是上述两个方案中用到的权限范围。

关键注意事项

  • RBAC权限配置:必须给登录用户分配Blob存储的RBAC角色(如「存储Blob数据读者」「存储Blob数据参与者」),而非仅给托管身份分配权限。
  • 令牌过期处理:用户访问令牌有过期时间(默认1小时),用Easy Auth时可通过/.auth/refresh端点刷新;用MSAL时可调用acquire_token_silent自动刷新令牌。
  • 托管身份的用途:如果应用需要执行用户无关的后台操作(如定时清理Blob),可保留托管身份的权限,但用户操作必须用用户令牌。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:40:08