Azure java.lang.IllegalArgumentException:除非ServiceClient使用帐户密钥凭据,否则无法创建共享访问签名

Azure java.lang.IllegalArgumentException:除非ServiceClient使用帐户密钥凭据,否则无法创建共享访问签名,azure,azure-devops,azure-storage-blobs,azure-managed-identity,Azure,Azure Devops,Azure Storage Blobs,Azure Managed Identity,我正在尝试使用MSI访问Azure Blob存储容器以生成共享访问签名。但每次我尝试访问时,都会出现以下错误: `java.lang.IllegalArgumentException: Cannot create Shared Access Signature unless the Account Key credentials are used by the ServiceClient.` 我不想使用凭据或AAD访问blob存储容器。只想使用MSI,因为这是我们希望在应用程序中适应的唯一模

我正在尝试使用MSI访问Azure Blob存储容器以生成共享访问签名。但每次我尝试访问时,都会出现以下错误:

`java.lang.IllegalArgumentException: Cannot create Shared Access Signature unless the Account Key credentials are used by the ServiceClient.` 
我不想使用凭据或AAD访问blob存储容器。只想使用MSI,因为这是我们希望在应用程序中适应的唯一模式,以访问Azure资源。我错过了什么。我在Splunk日志中检查了MSI令牌正在成功生成。下面是我创建CloudBlobClient以访问Blob容器的方式:

public CloudBlobClient cloudBlobClient() throws URISyntaxException {
    String storageAccountName = propertyUtil.getStorageAccountName();
    // Implemented some logic in AzureStorageMSICredential class to fetch access 
    // token, and its working correctly
    String msiToken = azureStorageMSICredentials.getToken();
    LOG.info("Initiating CloudBlobClient.... msitoken = " + msiToken);
    StorageCredentials storageCredentials =
      new StorageCredentialsToken(storageAccountName, msiToken);

    URI storageAccountURI = URIUtils.getStorageAccountURI(storageAccountName);
    CloudBlobClient cloudBlobClient = new CloudBlobClient(storageAccountURI, 
      storageCredentials);
    return cloudBlobClient;
  }

我在stackoverflow上搜索了很多线程,这看起来像是这个线程的重复,但实际上不是。有些是2017年的。

通过查看Azure Storage Java SDK,我发现generateSharedAccessSignature方法最终将调用以下内容:

public String generateSharedAccessSignature(
        final SharedAccessBlobPolicy policy, final SharedAccessBlobHeaders headers,
        final String groupPolicyIdentifier, final IPRange ipRange, final SharedAccessProtocols protocols)
        throws InvalidKeyException, StorageException {

    if (!StorageCredentialsHelper.canCredentialsSignRequest(this.blobServiceClient.getCredentials())) {
        throw new IllegalArgumentException(SR.CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY);
    }

    final String resourceName = this.getCanonicalName(true);

    final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForBlobAndFile(
            policy, headers, groupPolicyIdentifier, resourceName, ipRange, protocols, this.blobServiceClient,
            this.isSnapshot() ? Constants.QueryConstants.BLOB_SNAPSHOT_SERVICE : Constants.QueryConstants.BLOB_RESOURCE,
            this.getSnapshotID());

    final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForBlobAndFile(
            policy, headers, groupPolicyIdentifier,
            this.isSnapshot() ? Constants.QueryConstants.BLOB_SNAPSHOT_SERVICE : Constants.QueryConstants.BLOB_RESOURCE,
            ipRange, protocols, signature);

    return builder.toString();
}
签名字符串是Hmac256字符串。StorageCredentialsHelper中有一个方法可以计算它

public static synchronized String computeHmac256(final StorageCredentials creds, final String value) throws InvalidKeyException {
    if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
        byte[] utf8Bytes = null;
        try {
            utf8Bytes = value.getBytes(Constants.UTF8_CHARSET);
        }
        catch (final UnsupportedEncodingException e) {
            throw new IllegalArgumentException(e);
        }
        return Base64.encode(((StorageCredentialsAccountAndKey) creds).getHmac256().doFinal(utf8Bytes));
    }
    else {
        return null;
    }
}
在此方法中,需要StorageCredentialsAccountAndKey。它是一个密钥,可用于对数据进行签名。但是,当您使用MSI作为身份验证时,您使用的令牌实际上是一个AAD访问令牌,不能用于在此位置签名。您可以使用以下代码进行检查:

StorageCredentials credentials = blobClient.getCredentials();
System.out.println(credentials.toString(true));
因此,在generateSharedAccessSignature方法中,将抛出一个错误:

    if (!StorageCredentialsHelper.canCredentialsSignRequest(this.blobServiceClient.getCredentials())) {
        throw new IllegalArgumentException(SR.CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY);
    }

总之,如果当前使用MSI作为身份验证,则无法生成SharedAccessSignature。您可以将您的请求发布到。如果您的请求被否决,开发团队可能会添加此功能

通过查看Azure Storage Java SDK,我发现generateSharedAccessSignature方法最终将调用以下内容:

public String generateSharedAccessSignature(
        final SharedAccessBlobPolicy policy, final SharedAccessBlobHeaders headers,
        final String groupPolicyIdentifier, final IPRange ipRange, final SharedAccessProtocols protocols)
        throws InvalidKeyException, StorageException {

    if (!StorageCredentialsHelper.canCredentialsSignRequest(this.blobServiceClient.getCredentials())) {
        throw new IllegalArgumentException(SR.CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY);
    }

    final String resourceName = this.getCanonicalName(true);

    final String signature = SharedAccessSignatureHelper.generateSharedAccessSignatureHashForBlobAndFile(
            policy, headers, groupPolicyIdentifier, resourceName, ipRange, protocols, this.blobServiceClient,
            this.isSnapshot() ? Constants.QueryConstants.BLOB_SNAPSHOT_SERVICE : Constants.QueryConstants.BLOB_RESOURCE,
            this.getSnapshotID());

    final UriQueryBuilder builder = SharedAccessSignatureHelper.generateSharedAccessSignatureForBlobAndFile(
            policy, headers, groupPolicyIdentifier,
            this.isSnapshot() ? Constants.QueryConstants.BLOB_SNAPSHOT_SERVICE : Constants.QueryConstants.BLOB_RESOURCE,
            ipRange, protocols, signature);

    return builder.toString();
}
签名字符串是Hmac256字符串。StorageCredentialsHelper中有一个方法可以计算它

public static synchronized String computeHmac256(final StorageCredentials creds, final String value) throws InvalidKeyException {
    if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
        byte[] utf8Bytes = null;
        try {
            utf8Bytes = value.getBytes(Constants.UTF8_CHARSET);
        }
        catch (final UnsupportedEncodingException e) {
            throw new IllegalArgumentException(e);
        }
        return Base64.encode(((StorageCredentialsAccountAndKey) creds).getHmac256().doFinal(utf8Bytes));
    }
    else {
        return null;
    }
}
在此方法中,需要StorageCredentialsAccountAndKey。它是一个密钥,可用于对数据进行签名。但是,当您使用MSI作为身份验证时,您使用的令牌实际上是一个AAD访问令牌,不能用于在此位置签名。您可以使用以下代码进行检查:

StorageCredentials credentials = blobClient.getCredentials();
System.out.println(credentials.toString(true));
因此,在generateSharedAccessSignature方法中,将抛出一个错误:

    if (!StorageCredentialsHelper.canCredentialsSignRequest(this.blobServiceClient.getCredentials())) {
        throw new IllegalArgumentException(SR.CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY);
    }
总之,如果当前使用MSI作为身份验证,则无法生成SharedAccessSignature。您可以将您的请求发布到。如果您的请求被否决,开发团队可能会添加此功能