Azure.Data.Tables 方法 - 如何从使用共享密钥 + Uri 更改为托管 ID?

Azure.Data.Tables method - how to change from using shared key + Uri to managed Id?

我有一个 Azure 函数(HTTP 触发器)可以写入队列,也可以写入存储 table。 它一直运行良好,但现在我需要将所有内容移至使用托管身份。

我能够将 HTTP 触发器更改为使用 __serviceUri 环境变量进行连接,而不是使用连接字符串。但现在我需要弄清楚如何更新写入存储 table.

的逻辑

这是相关代码。
HTTP 触发器

[FunctionName("Createwidget")]
    public async Task<IActionResult> Createwidget(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "toys/widgets")] HttpRequest req,
         [Queue("widgets"), StorageAccount("ExtStorageQueue")] ICollector<string> messageQueue,
        ILogger log)
    {           
        widgetResponse response = new widgetResponse();
        var content = await new StreamReader(req.Body).ReadToEndAsync();
        log.LogInformation($"Received following payload: {content}");

        var widgetRequest = JsonConvert.DeserializeObject<widget>(content);
        if (widgetRequest.name != null){     
                
                messageQueue.Add(JsonConvert.SerializeObject(widgetRequest));  
                // this is where I need to update the code              
                response = await storage.ProvisioningRequest(widgetRequest, req.HttpContext.Items["MS_AzureFunctionsRequestID"].ToString(), "enqueued");                
        } 
        else {
            response.status = "Error: Invalid Request";
            response.requestId=null;
        }
        return new OkObjectResult(JsonConvert.SerializeObject(response));  
    }

这是来自 storage.ProvisioningRequest()

的片段
GetStorageAccountConnectionData
var serviceClient = new TableServiceClient(
new Uri(connection.storageUri),
new TableSharedKeyCredential(connection.storageAccountName, connection.storageAccountKey));
var tableClient = serviceClient.GetTableClient(connection.tableName);
await tableClient.CreateIfNotExistsAsync();

这是我创建连接的方式:

    private void GetStorageAccountManagedIDConnection()
    {
        var azureWebJobsStorage = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
        String[] accountDetailsArray = azureWebJobsStorage.Split(";");
        String[] accountNameArray = accountDetailsArray[1].Split("=");
        connection.storageAccountName = accountNameArray[1];

        var storageAccount= Environment.GetEnvironmentVariable("ExtStorageQueue");
        String[] storageAccountDetailsArray = storageAccount.Split(";");
        String[] accountKeyDetailsArray = storageAccountDetailsArray[2].Split("AccountKey=");
        string storageKey = accountKeyDetailsArray[1];
        connection.tableName = Environment.GetEnvironmentVariable("squeueTable");
        connection.storageUri = $"https://{connection.storageAccountName}.table.core.windows.net/{connection.tableName}";
        connection.storageAccountKey = storageKey;
    }

这是我的 local.settings.json 文件的样子:

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=mystorageAccountName;EndpointSuffix=core.windows.net;AccountKey=supersecretKey/asdf+asdf==",
    "squeueTable": "provisionedWidgets",
    "ExtStorageQueue__serviceUri": "https://mystorageAccountName.queue.core.windows.net",
   
  },
  "ConnectionStrings": {}
}

有办法吗?我一直在阅读 https://docs.microsoft.com/en-us/dotnet/api/azure.data.tables.tableclient?view=azure-dotnet#constructors,但我没有看到任何允许我使用托管 ID

的构造函数

任何帮助将不胜感激

编辑 1

这是创建连接配置数据的简化方法:

    private void GetStorageAccountConnectionData()
    {
        //TODO:  remove hardcoded values and extract from local.settings.json instead.  For testing purposes only to see how serivceUri works.
        connection.storageAccountName = "mystorageaccountname";
        connection.tableName = Environment.GetEnvironmentVariable("StorageTableName");
        connection.storageTableUri = $"https://{connection.storageAccountName}.table.core.windows.net/{connection.tableName}";
        connection.storageQueueUri = $"https://{connection.storageAccountName}.queue.core.windows.net/";
    }

这是使用它的逻辑:

           GetStorageAccountConnectionData();
              var serviceClient = new TableServiceClient(new Uri(connection.storageTableUri), new DefaultAzureCredential());
            var tableClient = serviceClient.GetTableClient(connection.tableName);
            TableEntity origEntity = tableClient.GetEntity<TableEntity>(
                                ENQUEUED_PARTITION,
                                notification.requestId);

没有编译错误,但未写入存储table。
我目前正在尝试查看有关创建调试消息/日志的信息,因为我无法让我的本地调试环境正常工作

编辑 2

我终于设置了本地环境,以便进行调试。所以写入我的存储队列的逻辑是有效的,但是当我尝试写入存储 table 时,我现在可以看到完整的错误是什么。这是错误:

Failed to create storage record:Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.                                                                                                                                                                    ure.
RequestId:asdf-0002-asdf-6574-asdf
Time:2022-05-10T13:45:24.6319496Z
Status: 403 (Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.)
ErrorCode: AuthenticationFailed

Content:
{"odata.error":{"code":"AuthenticationFailed","message":{"lang":"en-US","value":"Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including 
is formed correctly including the signature.\nRequestId:9f775fd8-0002-002c-6574-648209000000\nTime:2022-05-10T13:45:24.6319496Z"}}}

Headers:
Server: Microsoft-HTTPAPI/2.0
x-ms-request-id: asdf-asdf-asdf-asdf
x-ms-error-code: REDACTED
Date: Tue, 10 May 2022 13:45:23 GMT
Content-Length: 299
Content-Type: application/json

还要明确一点,当我在云中测试时也会发生同样的行为。所以不管我叫

 POST https://myfunctionapp.azurewebsites.net/widgets/workspaces

 POST http://localhost:7071/widgets/workspaces

这是相同的行为。存储队列已更新,但 table.

未更新

就托管 ID 而言,它现在具有以下权限:

您需要添加对这些包的引用:

您的功能应用程序将需要 Storage Account ContributorContributor 存储级别的角色(说实话不确定)。

下面是您的代码的一个片段:

var serviceClient = new TableServiceClient(
  new Uri(connection.storageUri), new DefaultAzureCredential());
var tableClient = serviceClient.GetTableClient (connection.tableName);
await tableClient.CreateIfNotExistsAsync();