Azure ShareClient:此请求无权执行此操作

问题描述 投票:0回答:1

我正在尝试使用 Azure ShareFile 客户端通过函数应用程序将数据从 SQL Server 表导出到 XLSX 文件。当我在本地 VSCode 中运行代码时,文件已成功创建。我相信这一成功可以归因于我是存储帐户的所有者。当代码在计算机上执行时,Azure 使用我的登录名进行身份验证。但是,部署到云的 Azure 函数应用程序中导出失败并出现 403 授权错误。

初始化ShareFile客户端的代码如下:

def getFileClient(filePath):
    accountName = accountKey = os.environ["AZURE_STORAGE_ACCOUNT_NAME"]
    accountKey = os.environ["AZURE_STORAGE_ACCOUNT_KEY"]
    connectStr = os.environ["AZURE_STORAGEFILE_CONNECTIONSTRING"]

    shareName = "dev"

    sasToken = generate_account_sas(
        account_name=accountName,
        account_key=accountKey,
        resource_types=ResourceTypes(service=True, object=True),
        permission=AccountSasPermissions(read=True, write=True),
        expiry=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=1),
        services=Services(fileshare=True)
    )
    shareClient = ShareClient.from_connection_string(conn_str=connectStr, share_name=shareName, credential=sasToken)

    # Get a reference to the file
    fileClient = shareClient.get_file_client(filePath)
    return(fileClient)

导出数据到XLSX文件的代码如下:

XLBytes = BytesIO()
dataMartDF[export_cols].to_excel(XLBytes, index=False)
XLBytes.seek(0)
countyDispFC.create_file(size=XLBytes.getbuffer().nbytes)
countyDispFC.upload_file(XLBytes)

其中 CountyDispFC 是 getFileClient 函数返回的文件客户端。

通过 https 调用该函数时会记录以下错误: 错误日志摘录

请注意,网络设置包括“从选定的虚拟网络和 IP 地址启用”。我已经添加了我的本地机器的IP地址和功能应用程序的公共IP地址。

我还创建了一个托管身份,将其分配给函数应用程序,并授予其存储帐户中的存储文件特权贡献者角色(IAM 中的托管身份角色)。我更愿意使用此托管身份进行访问,但当我尝试创建凭证对象并在 ShareClient 函数中使用它时,遇到了“需要 token_intent”错误。

我错过了什么?

azure-functions authorization azure-storage azure-managed-identity azure-file-share
1个回答
0
投票

网络设置包括“从选定的虚拟网络和 IP 地址启用”。我已添加本地计算机的 IP 地址和函数应用程序的公共 IP 地址。没有其他网络设置、虚拟网络、专用端点等

设置此设置后,您需要将存储帐户和功能连接到虚拟网络,然后只有它才能工作,下面的方法对我有用:

首先,创建一个 Function 应用并启用托管身份:

enter image description here

然后将V-net链接到存储帐户:

enter image description here

现在将 V-net 链接到 Function App :

单击“未配置”:

enter image description here

链接后:

enter image description here

注意:确保存储帐户、功能应用程序和 vnet 位于同一位置。

建立从 Function 应用程序到存储帐户的连接,您可以在 Function 应用程序子网中启用 Microsoft.storage 服务端点:

enter image description here

部署以下代码:

import os
import logging
from io import BytesIO
import azure.functions as func
import pandas as ch
from azure.identity import DefaultAzureCredential
from azure.storage.fileshare import ShareClient

def ri_gt_cl(file_path):
    
    ri_acc_nme = "tset123"
    ri_cs="DefaultEndpointsProtocol=https;AccountName=filehh;AccountKey=/aQKGeeEsa43klLpgjQ==;EndpointSuffix=core.windows.net"
    rith_file_share = "rithfile"  
    ri_scl = ShareClient(
        account_url=f"https://{ri_acc_nme}.file.core.windows.net/",
        conn_str=ri_cs,
        share_name=rith_file_share
    )
    r_ch = ri_scl.get_file_client(file_path)
    return r_ch

import os
import logging
from io import BytesIO
import azure.functions as func
import pandas as ch
from azure.storage.fileshare import ShareClient

def ri_gt_cl(file_path):
    
    ri_cs = "DefaultEndpointsProtocol=https;AccountName=tset123;AccountKey=d+t5237NGVidW+AStjkzsFA==;EndpointSuffix=core.windows.net"
    ri_file_shr_name = "rithfile"  
    risl = ShareClient.from_connection_string(
        conn_str=ri_cs,
        share_name=ri_file_shr_name
    )

    ri_fcl = risl.get_file_client(file_path)
    return ri_fcl

def ri_up():
    
    ri_dt = {
        "Name": ["Rithwik", "Chotu"],
        "Age": [8, 7]
    }
    rid = ch.DataFrame(ri_dt)
    ri_ex_b = BytesIO()
    rid.to_excel(ri_ex_b, index=False)
    ri_ex_b.seek(0)
    rifp = "rithtest.xlsx" 
    rifl = ri_gt_cl(rifp)
    fs = ri_ex_b.getbuffer().nbytes
    rifl.create_file(size=fs)
    rifl.upload_file(ri_ex_b)

    return f"Hello Rithwik, File Uploaded '{rifp}'"

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info("Hello Rithwik, Function Started")
    try:
        ri_out = ri_up()
        return func.HttpResponse(
            f"Success: {ri_out}",
            status_code=200
        )
    except Exception as ri:
        logging.error(f"Hello Rithwik, there is an error: {str(ri)}")
        return func.HttpResponse(f"Hello Rithwik, Error is:  {str(ri)}",status_code=500)

输出:

执行的功能应用程序:

enter image description here

在存储帐户中下载文件:

enter image description here

文件:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.