java - 如何在Java中基于SAS Token访问Azure WASB容器?

标签 java azure azure-storage azure-blob-storage

我正在尝试使用 SAS key 以 Java 代码从 Azure WASB 检索容器。这是在 HDFS 代码中完成的,但出于某种原因我似乎无法让它工作。我已设法将其简化为下面的应用程序,但这也不起作用。我认为这要么是我们如何生成 SAS token 的问题,要么是 Azure 帐户权限的问题。有人可以看看这个并为我指明问题可能是什么的正确方向吗?谢谢!

public static void main(String[] arguments)
{
    try {
        String storage_account = "wasbvalidation";
        String container = "demoengagement1";
        CloudBlobClient blobClient = getBlobClient(storage_account);

        CloudBlobContainer blobContainer = blobClient.getContainerReference(container);

        blobContainer.downloadAttributes(); // This call succeeds

        SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy();
        policy.setPermissions(EnumSet.allOf(SharedAccessBlobPermissions.class));
        policy.setSharedAccessStartTime(Date.valueOf(LocalDate.now().minusYears(2)));
        policy.setSharedAccessExpiryTime(Date.valueOf(LocalDate.now().plusYears(2)));

        String sas = blobContainer.getUri().toString() + "?" + blobContainer.generateSharedAccessSignature(policy, null, null, SharedAccessProtocols.HTTPS_ONLY);

        // Code after this point is emulating what HDFS is doing, so I'd rather not change it.
        URI blobUri = new URI(blobContainer.getUri().toString());
        StorageCredentials credentials = new StorageCredentialsSharedAccessSignature(sas);
        CloudBlobContainer sasContainer = new CloudBlobContainer(blobUri, credentials);
        sasContainer.downloadAttributes(); // This call fails, however.
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static CloudBlobClient getBlobClient(String storageAccount) throws NullPointerException {
    String storageConnectionString = "DefaultEndpointsProtocol=https;" + "AccountName=" + storageAccount + ";" + "AccountKey=" + accountKey;
    CloudStorageAccount csa = null;
    try {
        csa = CloudStorageAccount.parse(storageConnectionString);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    CloudBlobClient blobClient = csa.createCloudBlobClient();
    return blobClient;
}

最佳答案

根据您的代码,我认为您希望通过使用 SAS 为容器构建 url 来获取 Blob 容器的属性和元数据。但是,SharedAccessBlobPolicy 生成的 SAS 字符串类似于 sig=1G7tiQnLEtbjk2RSNuUSKH7gLNVZjqhuLQL%2Fci%2FXS50%3D&st=2017-01-30T16%3A00%3A00Z&se=2021-01-30T16%3A00%3A0 0Z&sv= 2018-03-28&sp=racwdl&sr=b 用于 blob (sr=b),不适用于容器 (sr=c,例如 st= 2019-01-31T08%3A38%3A46Z&se=2019-02-01T08%3A38%3A46Z&sp=rl&sv=2018-03-28&sr=c&sig=KnynNYBUtzNSYtBEcYakMrhAXPRIk60wztB3BFv5b%2Bs%3D 从 Azure 复制存储资源管理器)。

我尝试将 CloudStorageAccountSharedAccessAccountPolicy 结合使用来生成 Account SAS通过下面的代码获取 blob,但它仍然不起作用。

Account SAS. The account SAS delegates access to resources in one or more of the storage services. All of the operations available via a service SAS are also available via an account SAS. Additionally, with the account SAS, you can delegate access to operations that apply to a given service, such as Get/Set Service Properties and Get Service Stats. You can also delegate access to read, write, and delete operations on blob containers, tables, queues, and file shares that are not permitted with a service SAS. See Constructing an Account SAS for in-depth information about constructing the account SAS token.

SharedAccessAccountPolicy accountPolicy = new SharedAccessAccountPolicy();
accountPolicy.setPermissions(EnumSet.allOf(SharedAccessAccountPermissions.class));
accountPolicy.setSharedAccessStartTime(Date.valueOf(LocalDate.now().minusYears(2)));
accountPolicy.setSharedAccessExpiryTime(Date.valueOf(LocalDate.now().plusYears(2)));

String sas = csa.generateSharedAccessSignature(accountPolicy);

我测试了下面的代码,

StorageCredentials credentials = new StorageCredentialsSharedAccessSignature(sas);
CloudBlobContainer sasContainer = new CloudBlobContainer(new URI(container2.getUri().toString()+"?"+sas), credentials);
sasContainer.downloadAttributes();

然后获取异常。

Exception in thread "main" java.lang.IllegalArgumentException: Cannot provide credentials as part of the address and as constructor parameter. Either pass in the address or use a different constructor.

或者测试代码 CloudBlobContainer sasContainer = new CloudBlobContainer(new URI(container2.getUri().toString()+"?"+sas)) 来获取异常。

Exception in thread "main" com.microsoft.azure.storage.StorageException: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

我研究了SDK源代码后,似乎是由于Azure Java Storage SDK v8.0.0的实现导致的。也许您可以向 Microsoft 报告此问题。

我尝试通过下面的代码使用 Azure Java Storage SDK v10 生成带有 SAS 的容器 URL,效果很好。

v10 的 Maven 依赖项:

<!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-storage-blob -->
<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-storage-blob</artifactId>
    <version>10.4.0</version>
</dependency>

使用 SAS 生成容器 URL 的代码:

String accountName = "<your account name>";
String accountKey = "<your account key>";
SharedKeyCredentials credentials = new SharedKeyCredentials(accountName, accountKey);
final ServiceURL serviceURL = new ServiceURL(new URL("http://" + accountName + ".blob.core.windows.net"), StorageURL.createPipeline(credentials, new PipelineOptions()));
String containerName = "<container name>";
ServiceSASSignatureValues values = new ServiceSASSignatureValues()
                .withProtocol(SASProtocol.HTTPS_ONLY) // Users MUST use HTTPS (not HTTP).
                .withExpiryTime(OffsetDateTime.now().plusDays(2)) // 2 days before expiration.
                .withContainerName(containerName)
                .withBlobName(blobName);
ContainerSASPermission permission = new ContainerSASPermission()
                .withRead(true)
                .withAdd(true)
                .withWrite(true);
values.withPermissions(permission.toString());
SASQueryParameters serviceParams = values.generateSASQueryParameters(credentials);
String sas = serviceParams.encode();

String containerUrlWithSAS = String.format(Locale.ROOT, "https://%s.blob.core.windows.net/%s%s",
                accountName, containerName, sas);
HttpPipeline pipeline = new HttpPipelineBuilder().build();
ContainerURL sasContainer = new ContainerURL(new URL(containerUrlWithSAS), pipeline);
sasContainer.getProperties();

注意:SDK v10ContainerURLgetProperties功能与CloudBlobContainer的downloadAttributes类似SDK v8 中的 ,它还会返回容器的元数据和系统属性。

关于java - 如何在Java中基于SAS Token访问Azure WASB容器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54444129/

相关文章:

powershell - AzureAD powershell 新服务主体

Java - 从 for 循环返回信息

java - 如何累积属性占位符?

java - 读取文件: File name not working

azure - 无法为现有虚拟网络创建网关

python - Azure Python SDK 凭据刷新

azure - 我是否可以对 Azure 存储进行 API 调用来判断我的容器是否已被删除?

c# - 当引用的 .NET 依赖项版本不匹配时,如何解析引用?

asp.net-mvc - Azure 存储 api 不适用于 asnyc 上传

java - 如何创建表示对象的 XML 属性