通过 Xamarin 上的 SAS 访问 Azure table 时授权失败

Authorization Failure when accessing Azure table via SAS on Xamarin

我已经设置了自定义 API 来为我的 Xamarin 应用程序生成 SAS 令牌。在应用程序上收到令牌后,我连接到 table 并尝试 运行.ExistsAsync() 以确认我可以与 table 通信。我正在 运行 遇到一个问题,我已经正确生成了 SAS(虽然我想知道 start/end 时间是否关闭),但是当我尝试调用时出现授权失败存在异步()。下面列出了我生成的 SAS API、调用 ExistsAsync() 的 Xamarin 应用程序方法以及我收到的错误消息。

为 SAS 生成自定义 API:

module.exports = {
    "post": function (req, res, next) {
        var azure = require('azure-storage');
        var tableName = req.body.Table;

        // First 2 parameters are account name and key for your service
        var tableService = azure.createTableService('ACCOUNT_NAME', 'ACCOUNT_KEY', 'ACCOUNT_URL');

        // creating the table we want the token for - on the off chance it's not there yet
        tableService.createTableIfNotExists(tableName, function (err, result, response) {
            if (!err) {
                var expiryDate = new Date();
                var startDate = new Date();
                expiryDate.setMinutes(startDate.getMinutes() + 100);
                startDate.setMinutes(startDate.getMinutes() - 100);

                var sharedAccessPolicy = {
                    AccessPolicy: {
                        Permissions: 'raud', // requesting read, add, update and delete
                        Start : startDate,
                        Expiry: expiryDate
                    },
                };

                var tableSAS = tableService.generateSharedAccessSignature(tableName, sharedAccessPolicy);
                res.send(200, { Token : tableSAS });
            } else {
                res.send(500, { Token : "Error creating table"});
            }  
        });
    }
};

Table 连接的 Xamarin 应用程序代码(调用 TestDataConnection()):

public async Task<bool> TestDataConnection()
{
    if( tableClient == null ) {
        await ConnectToDatabase();
    }
    CloudTable table = tableClient.GetTableReference("MeasurementJournal");
    bool exists = false;
    try {
        exists = await table.ExistsAsync();
    } catch (Exception e) {
        Debug.WriteLine("Error checking if table exists: " + e.ToString());
    }
    return exists;
}

private async Task<bool> ConnectToDatabase()
{
    // Get credentials
    var credentials = await GetStorageCredentials();

    // Create client
    tableClient = new CloudTableClient(new Uri(Utility.ProjectConstants.tableServiceUrl), credentials);

    return true;
}

/**
 * GetStorageCredentials
 * 
 * Gets storage credentials from sas custom API
 */
private async Task<StorageCredentials> GetStorageCredentials()
{
    string token = "NULL";

    try {
        MobileServiceClient serviceClient = new MobileServiceClient(ACCOUNT_URL);

        //create req
        Model.SasRequest req = new Model.SasRequest();
        req.Table = "MeasurementJournal";

        //send req
        Model.SasResponse response = await serviceClient.InvokeApiAsync<Model.SasRequest, Model.SasResponse>(API_EXTENSION, req, HttpMethod.Post, null);

        //save token from response
        token = response.Token;
    } catch (Exception e) {
        Debug.WriteLine("Received exception: " + e.ToString());
    }
    return new StorageCredentials(token);
}

错误信息:

01-07 16:13:22.374 28311 28311 I mono-stdout: Error checking if table exists: Microsoft.WindowsAzure.Storage.WrappedStorageException (0x80041193): <?xml version="1.0" encoding="utf-16"?>
01-07 16:13:22.374 28311 28311 I mono-stdout: <!--An exception has occurred. For more information please deserialize this message via RequestResult.TranslateFromExceptionMessage.-->
01-07 16:13:22.374 28311 28311 I mono-stdout: <RequestResult>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <HTTPStatusCode>403</HTTPStatusCode>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <HttpStatusMessage>Forbidden</HttpStatusMessage>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <TargetLocation>Primary</TargetLocation>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <ServiceRequestID>f90ae37f-0002-0030-1d33-693dbe000000</ServiceRequestID>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <ContentMd5 />
01-07 16:13:22.374 28311 28311 I mono-stdout:   <Etag />
01-07 16:13:22.374 28311 28311 I mono-stdout:   <RequestDate>Sat, 07 Jan 2017 16:13:22 GMT</RequestDate>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <StartTime>Sat, 07 Jan 2017 22:13:21 GMT</StartTime>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <EndTime>Sat, 07 Jan 2017 22:13:22 GMT</EndTime>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <Error>
01-07 16:13:22.374 28311 28311 I mono-stdout:     <Code>AuthorizationFailure</Code>
01-07 16:13:22.374 28311 28311 I mono-stdout:     <Message>This request is not authorized to perform this operation.
01-07 16:13:22.374 28311 28311 I mono-stdout: RequestId:f90ae37f-0002-0030-1d33-693dbe000000
01-07 16:13:22.374 28311 28311 I mono-stdout: Time:2017-01-07T22:13:22.5850271Z</Message>
01-07 16:13:22.374 28311 28311 I mono-stdout:   </Error>
01-07 16:13:22.374 28311 28311 I mono-stdout:   <ExceptionInfo>
01-07 16:13:22.374 28311 28311 I mono-stdout:     <Type />
01-07 16:13:22.374 28311 28311 I mono-stdout:     <HResult>-2146233088</HResult>
01-07 16:13:22.374 28311 28311 I mono-stdout:     <Message>Unexpected response code, Expected:OK or NotFound, Received:Forbidden</Message>
01-07 16:13:22.374 28311 28311 I mono-stdout:     <Source>Microsoft.WindowsAzure.Storage</Source>
01-07 16:13:22.374 28311 28311 I mono-stdout:     <StackTrace>  at Microsoft.WindowsAzure.Storage.Core.Executor.Executor+&lt;ExecuteAsyncInternal&gt;d__6`1[T].MoveNext () [0x0095a] in &lt;b3bed838f8344d41a1a82c4a3b228bac&gt;:0 </StackTrace>
01-07 16:13:22.374 28311 28311 I mono-stdout:   </ExceptionInfo>
01-07 16:13:22.374 28311 28311 I mono-stdout: </RequestResult> ---> Microsoft.WindowsAzure.Storage.StorageException: Unexpected response code, Expected:OK or NotFound, Received:Forbidden
01-07 16:13:22.374 28311 28311 I mono-stdout:   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor+<ExecuteAsyncInternal>d__6`1[T].MoveNext () [0x0095a] in <b3bed838f8344d41a1a82c4a3b228bac>:0
01-07 16:13:22.374 28311 28311 I mono-stdout: Request Information
01-07 16:13:22.374 28311 28311 I mono-stdout: RequestID:f90ae37f-0002-0030-1d33-693dbe000000
01-07 16:13:22.374 28311 28311 I mono-stdout: RequestDate:Sat, 07 Jan 2017 16:13:22 GMT
01-07 16:13:22.374 28311 28311 I mono-stdout: StatusMessage:Forbidden
01-07 16:13:22.374 28311 28311 I mono-stdout: ErrorCode:AuthorizationFailure

我相信您发现了库中的一个错误。我能够重现此错误。我建议在 Github.

上提出同样的问题

同时,另一种检查 table 是否存在的方法是查询 table 并尝试只获取一条记录。 table 是空的还是包含任何记录都没有关系。如果table不存在,运行会报404错误。

这是一个示例代码:

        var cred = new StorageCredentials(accountName, accountKey);
        var account = new CloudStorageAccount(cred, true);
        var client = account.CreateCloudTableClient();
        var table = client.GetTableReference("Hello1");
        var sas = table.GetSharedAccessSignature(new SharedAccessTablePolicy()
        {
            Permissions = SharedAccessTablePermissions.Query,
            SharedAccessExpiryTime = DateTime.UtcNow.AddDays(1),
            SharedAccessStartTime = DateTime.UtcNow.AddDays(-1)
        });
        var tableClient = new CloudTableClient(account.TableEndpoint, new StorageCredentials(sas));
        table = tableClient.GetTableReference("Hello1");
        var queryResult = table.ExecuteQuerySegmented(new TableQuery()
        {
            TakeCount = 1
        }, null);

CloudTable.ExistsAysnc() 调用 Query Tables REST API,因此具有 QueryEntity 权限的 table SAS 无权执行此操作。您需要帐户密钥或帐户 SAS 才能使用 运行 CloudTable.ExistsAysnc() 方法。