简体   繁体   English

如何通过 Java/Spring-Boot 使用服务主体连接到 Azure Blob 存储

[英]How to connect to Azure Blob Storage using Service Principal with Java/Spring-Boot

I'm writing an application using Spring Boot and Java that will be writing files to Azure Blob Storage.我正在使用 Spring Boot 和 Java 编写一个将文件写入 Azure Blob 存储的应用程序。 How can I use a Service Principal to authenticate?如何使用服务主体进行身份验证? The details of the SP should ideally be read in via some properties or an external file.理想情况下,应通过某些属性或外部文件读取 SP 的详细信息。

I've been wading through the reams of documentation and examples, all of which don't seem to be quite what I'm looking for.我一直在翻阅大量的文档和示例,所有这些似乎都不是我想要的。 Most examples that I've seen use the Storage Account Key which I don't want to do.我见过的大多数示例都使用了我不想使用的存储帐户密钥。

Some example code would be really appreciated.一些示例代码将不胜感激。 As I said, I'm struggling to find a decent example (both of how to use an SP but also generally how to write to Azure BLOB Storage in Java) as there seems to be so many different ways of accessing storage scattered around in the microsoft docs.正如我所说,我正在努力寻找一个体面的示例(包括如何使用 SP,以及通常如何使用 Java 写入 Azure BLOB 存储),因为似乎有很多不同的方法可以访问分散在各处的存储微软文档。

You can use ADAL4J to acquire a token, and then use the token to write to blobs.您可以使用ADAL4J获取令牌,然后使用该令牌写入 Blob。

  1. Add role assignment to your principal.向您的委托人添加角色分配。

在此处输入图像描述

  1. Get token.获取令牌。

     public static String getToken() throws Exception { String TENANT_ID = "your tenant id or name, e4c9*-*-*-*-*57fb"; String AUTHORITY = "https://login.microsoftonline.com/" + TENANT_ID; String CLIENT_ID = "your application id, dc17*-*-*-*a5e7"; String CLIENT_SECRET = "the secret, /pG*32"; String RESOURCE = "https://storage.azure.com/"; String ACCESS_TOKEN = null; ExecutorService service = Executors.newFixedThreadPool(1); AuthenticationContext context = null; try { context = new AuthenticationContext(AUTHORITY, false, service); ClientCredential credential = new ClientCredential(CLIENT_ID, CLIENT_SECRET); Future<AuthenticationResult> future = context.acquireToken(RESOURCE, credential, null); ACCESS_TOKEN = future.get().getAccessToken(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } finally { service.shutdown(); } return ACCESS_TOKEN; }
  2. Access blob.访问 blob。

     public static void main(String[] args) throws Exception { String token = getToken(); StorageCredentialsToken credentialsToken = new StorageCredentialsToken("storagetest789", token); CloudBlobClient blobClient = new CloudBlobClient(new URI("https://storagetest789.blob.core.windows.net/"), credentialsToken); CloudBlobContainer blobContainer = blobClient.getContainerReference("pub"); CloudBlockBlob blockBlob = blobContainer.getBlockBlobReference("test.txt"); blockBlob.uploadText("Test!"); }

Hope it helps.希望能帮助到你。

I have created an article on connecting Spring Boot App with Azure Storage account using Serivce Principal you can refer that.我创建了一篇关于使用服务主体将 Spring Boot App 与 Azure 存储帐户连接的文章,您可以参考。

https://medium.com/@iamdeveshkumar/using-azure-blob-storage-with-a-spring-boot-app-6238c137df7 https://medium.com/@iamdeveshkumar/using-azure-blob-storage-with-a-spring-boot-app-6238c137df7

pom.xml pom.xml

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-storage-blob</artifactId>
    <version>12.12.0</version>
</dependency>

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-identity</artifactId>
    <version>1.3.1</version>
</dependency>

application.properties应用程序属性

app.config.azure.client-id=xxxxxxxxxxx
app.config.azure.client-secret=xxxxxxxxxxx
app.config.azure.tenant-id=xxxxxxxxxxx
app.config.azure.storage-id=xxxxxxxxxxx
app.config.azure.storage-endpoint=https://{STORAGE-ID}.blob.core.windows.net
app.config.azure.storage.container=xxxxxxxxxxx

AzureStorageConfiguration.java AzureStorageConfiguration.java

@Data
@Configuration
@Slf4j
public class AzureStorageConfiguration {
  private static final Logger logger = LoggerFactory.getLogger(AzureStorageConfiguration.class);

  @Value("${app.config.azure.client-id}")
  private String clientId;
  @Value("${app.config.azure.client-secret}")
  private String clientSecret;
  @Value("${app.config.azure.tenant-id}")
  private String tenantId;
  @Value("${app.config.azure.storage-id}")
  private String storageId;
  @Value("${app.config.azure.storage-endpoint}")
  private String storageEndpoint;
  @Value("${app.config.azure.storage.container}")
  private String storageContainer;

  /**
   * Blob service client builder blob service client builder.
   *
   * @return the blob service client builder
   */
  @Bean
  public BlobServiceClientBuilder blobServiceClientBuilder() {
    return new BlobServiceClientBuilder()
        .credential(getAzureClientCredentials())
        .endpoint(getStorageEndpoint());
  }

  private ClientSecretCredential getAzureClientCredentials() {
    return new ClientSecretCredentialBuilder()
        .clientId(clientId)
        .clientSecret(clientSecret)
        .tenantId(tenantId)
        .build();
  }

  /**
   * Gets storage endpoint.
   *
   * @return the storage endpoint
   */
  public String getStorageEndpoint() {
    return storageEndpoint.replace("{STORAGE-ID}", storageId);
  }

  /**
   * A util method to upload a file to Azure Storage.
   *
   * @param blobServiceClientBuilder service client builder
   * @return BlobServiceAsyncClient blob service async client
   */
  @Bean(name = "blobServiceAsyncClient")
  public BlobServiceAsyncClient blobServiceAsyncClient(
      BlobServiceClientBuilder blobServiceClientBuilder) {
    /*
    retryDelay is by default 4ms and maxRetryDelay is by default 120ms
     */
    return blobServiceClientBuilder.retryOptions(
        new RequestRetryOptions(
            RetryPolicyType.EXPONENTIAL,
            5,
            Duration.ofSeconds(300L),
            null,
            null,
            null)).buildAsyncClient();
  }
}

Then you can use the BlobServiceAsyncClient to create BlobAsyncClient for various blob operations.然后,您可以使用BlobServiceAsyncClient为各种 blob 操作创建BlobAsyncClient

/**
   * Get blob async client blob async client.
   *
   * @param container the container
   * @param blobName  the blob name
   * @return the blob async client
   */
  public BlobAsyncClient getBlobAsyncClient(String container, String blobName) {
    BlobContainerAsyncClient blobContainerAsyncClient =
        blobServiceAsyncClient.getBlobContainerAsyncClient(container);
    return blobContainerAsyncClient.getBlobAsyncClient(blobName);
  }


/**
   * Upload to azure blob.
   *
   * @param container the container
   * @param blobName  the blob name
   * @param data      the data
   */
  public void uploadToAzureBlob(String container, String blobName, byte[] data) {
    BlobAsyncClient blobAsyncClient = getBlobAsyncClient(container, blobName);
    long blockSize = 2L * 1024L * 1024L; //2MB
    blobAsyncClient.upload(covertByteArrayToFlux(data),
                           getTransferOptions(blockSize), true)
        .doOnSuccess(blockBlobItem -> logger.info("Successfully uploaded !!"))
        .doOnError(throwable -> logger.error(
            "Error occurred while uploading !! Exception:{}",
            throwable.getMessage()))
        .subscribe();
  }

/**
   * Covert byte array to flux flux.
   *
   * @param byteArray the byte array
   * @return the flux
   */
  public Flux<ByteBuffer> covertByteArrayToFlux(byte[] byteArray) {
    return Flux.just(ByteBuffer.wrap(byteArray));
  }

  /**
   * Creating TransferOptions.
   *
   * @param blockSize represents block size
   * @return ParallelTransferOptions transfer options
   */
  public ParallelTransferOptions getTransferOptions(long blockSize) {
    return new ParallelTransferOptions()
        .setBlockSizeLong(blockSize)
        .setMaxConcurrency(5)
        .setProgressReceiver(
            bytesTransferred -> logger.info("Uploading bytes:{}", bytesTransferred));
  }

For more details and code you can refer to my github repo更多细节和代码可以参考我的github repo

https://github.com/kdevesh/azure-storage-spring-boot-app https://github.com/kdevesh/azure-storage-spring-boot-app

PS I am using the async flavour of Blob Client there is a sync flavour also available if somebody wants to use that. PS 我正在使用 Blob Client 的异步风格,如果有人想使用它,也可以使用同步风格。

Another way to get the Access token is using the MS authentication lib获取访问令牌的另一种方法是使用 MS 身份验证库

This library used "builders" to build out the confidential client.该库使用“构建器”来构建机密客户端。 If you use that class, it handles refreshing the token for you and handles the cache如果您使用该类,它会为您处理刷新令牌并处理缓存

我用Jack Jia的方法,但是不行……我可以拿到token,但是上传的时候,有问题在这里输入图片描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM