【Azure|【Azure 存储服务】代码版 Azure Storage Blob 生成 SAS (Shared Access Signature: 共享访问签名)

问题描述 在使用Azure存储服务,为了有效的保护Storage的Access Keys。可以使用另一种授权方式访问资源(Shared Access Signature: 共享访问签名), 它的好处可以控制允许访问的IP过期时间权限 服务 等。Azure门户上提供了对Account级,Container级,Blob级的SAS生成服务。
【Azure|【Azure 存储服务】代码版 Azure Storage Blob 生成 SAS (Shared Access Signature: 共享访问签名)
文章图片


那么使用代码如何来生成呢?

问题回答 以最常见的两种代码作为示例:.NET 和 Java
.NET Blob SAS 将使用帐户访问密钥(Storage Account Key1 or Key2)进行签名。 使用 StorageSharedKeyCredential 类创建用于为 SAS 签名的凭据。 新建 BlobSasBuilder 对象,并调用 ToSasQueryParameters 以获取 SAS 令牌字符串。官方文档(https://docs.azure.cn/zh-cn/storage/blobs/sas-service-create?tabs=dotnet)中进行了详细介绍,直接使用以下部分代码即可生成Blob的SAS URL。

private static Uri GetServiceSasUriForBlob(BlobClient blobClient, string storedPolicyName = null) { // Check whether this BlobClient object has been authorized with Shared Key. if (blobClient.CanGenerateSasUri) { // Create a SAS token that's valid for one hour. BlobSasBuilder sasBuilder = new BlobSasBuilder() { BlobContainerName = blobClient.GetParentBlobContainerClient().Name, BlobName = blobClient.Name, Resource = "b" }; if (storedPolicyName == null) { sasBuilder.ExpiresOn = DateTimeOffset.UtcNow.AddHours(1); sasBuilder.SetPermissions(BlobSasPermissions.Read | BlobSasPermissions.Write); } else { sasBuilder.Identifier = storedPolicyName; }Uri sasUri = blobClient.GenerateSasUri(sasBuilder); Console.WriteLine("SAS URI for blob is: {0}", sasUri); Console.WriteLine(); return sasUri; } else { Console.WriteLine(@"BlobClient must be authorized with Shared Key credentials to create a service SAS."); return null; } }


JAVA 而Java的示例代码在官网中并没有介绍,所以本文就Java生成SAS的代码进行讲解。
从Java新版的SDK(azure-storage-blob)中 ,可以发现 BlobServiceClient,BlobContainerClient ,BlobClient 对象中都包含 generateAccountSas 或 generateSas 方法来实现对Account, Container,Blob进行SAS Token生成,只需要根据它所需要的参数对
AccountSasSignatureValues 和 BlobServiceSasSignatureValues 初始化。 示例代码( 全部代码可在文末下载):
public static void GenerateSASstring(BlobServiceClient blobServiceClient, BlobContainerClient blobContainerClient, BlobClient blobClient) { /* * Generate an account sas. Other samples in this file will demonstrate how to * create a client with the sas token. */ // Configure the sas parameters. This is the minimal set.OffsetDateTime startTime = OffsetDateTime.now(); OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); AccountSasService services = new AccountSasService().setBlobAccess(true); AccountSasResourceType resourceTypes = new AccountSasResourceType().setObject(true); SasProtocol protocol = SasProtocol.HTTPS_ONLY; SasIpRange sasIpRange = SasIpRange.parse("167.220.255.73"); // Generate the account sas. AccountSasPermission accountSasPermission = new AccountSasPermission().setReadPermission(true); AccountSasSignatureValues accountSasValues = new AccountSasSignatureValues(expiryTime, accountSasPermission, services, resourceTypes); accountSasValues.setStartTime(startTime); accountSasValues.setProtocol(protocol); accountSasValues.setSasIpRange(sasIpRange); String accountSasToken = blobServiceClient.generateAccountSas(accountSasValues); System.out.println("\nGenerate the account sas & url is :::: \n\t" + accountSasToken + "\n\t" + blobServiceClient.getAccountUrl() + "?" + accountSasToken); // Generate a sas using a container client BlobContainerSasPermission containerSasPermission = new BlobContainerSasPermission().setCreatePermission(true); BlobServiceSasSignatureValues serviceSasValues = new BlobServiceSasSignatureValues(expiryTime, containerSasPermission); serviceSasValues.setStartTime(startTime); serviceSasValues.setProtocol(protocol); serviceSasValues.setSasIpRange(sasIpRange); String containerSasToken = blobContainerClient.generateSas(serviceSasValues); System.out.println("\nGenerate the Container sas & url is :::: \n\t" + containerSasToken + "\n\t" + blobContainerClient.getBlobContainerUrl() + "?" + containerSasToken); // Generate a sas using a blob client BlobSasPermission blobSasPermission = new BlobSasPermission().setReadPermission(true); serviceSasValues = new BlobServiceSasSignatureValues(expiryTime, blobSasPermission); serviceSasValues.setStartTime(startTime); serviceSasValues.setProtocol(protocol); serviceSasValues.setSasIpRange(sasIpRange); String blobSasToken = blobClient.generateSas(serviceSasValues); System.out.println("\nGenerate the Blob sas & url is :::: \n\t" + blobSasToken + "\n\t" + blobClient.getBlobUrl() + "?" + blobSasToken); }

在pom.xml 中所需要加载的依赖项:
com.azure azure-storage-blob 12.13.0

以上代码中的各部分设置项 与 Azure门户上设置项的对应关系如下图:
【Azure|【Azure 存储服务】代码版 Azure Storage Blob 生成 SAS (Shared Access Signature: 共享访问签名)
文章图片


运行效果图

附录一:Java Main函数全部代码:
package test; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.URISyntaxException; import java.security.InvalidKeyException; import java.time.OffsetDateTime; import java.util.Iterator; import com.azure.storage.blob.BlobClient; import com.azure.storage.blob.BlobContainerClient; import com.azure.storage.blob.BlobServiceClient; import com.azure.storage.blob.BlobServiceClientBuilder; import com.azure.storage.blob.models.BlobItem; import com.azure.storage.blob.sas.BlobContainerSasPermission; import com.azure.storage.blob.sas.BlobSasPermission; import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.common.sas.AccountSasPermission; import com.azure.storage.common.sas.AccountSasResourceType; import com.azure.storage.common.sas.AccountSasService; import com.azure.storage.common.sas.AccountSasSignatureValues; import com.azure.storage.common.sas.SasIpRange; import com.azure.storage.common.sas.SasProtocol; /** * Hello world! * */ public class App { public static void main(String[] args) throws URISyntaxException, InvalidKeyException, RuntimeException, IOException { System.out.println("Hello World!"); String storageConnectionString = "DefaultEndpointsProtocol=https; AccountName=; AccountKey=**************************; EndpointSuffix=core.chinacloudapi.cn"; String blobContainerName = "test"; String dirName = ""; // Create a BlobServiceClient object which will be used to create a container System.out.println("\nCreate a BlobServiceClient Object to Connect Storage Account"); BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().connectionString(storageConnectionString) .buildClient(); // Create a unique name for the container String containerName = blobContainerName + java.util.UUID.randomUUID(); // Create the container and return a container client object System.out.println("\nCreate new Container : " + containerName); BlobContainerClient containerClient = blobServiceClient.createBlobContainer(containerName); // Create a local file in the ./data/ directory for uploading and downloadingSystem.out.println("\nCreate a local file in the ./data/ directory for uploading and downloading"); String localPath = "./data/"; String fileName = "quickstart" + java.util.UUID.randomUUID() + ".txt"; File localFile = new File(localPath + fileName); // Write text to the file FileWriter writer = new FileWriter(localPath + fileName, true); writer.write("Hello, World! This is test file to download by SAS. Also test upload"); writer.close(); // Get a reference to a blob BlobClient blobClient = containerClient.getBlobClient(fileName); System.out.println("\nUploading to Blob storage as blob:\n\t" + blobClient.getBlobUrl()); // Upload the blob blobClient.uploadFromFile(localPath + fileName); System.out.println("\nUpload blob completed : " + blobClient.getBlobName()); System.out.println("\nListing blobs..."); // List the blob(s) in the container. for (BlobItem blobItem : containerClient.listBlobs()) { System.out.println("\t" + blobItem.getName()); }// Download the blob to a local file // Append the string "DOWNLOAD" before the .txt extension so that you can see // both files. String downloadFileName = fileName.replace(".txt", "DOWNLOAD.txt"); File downloadedFile = new File(localPath + downloadFileName); System.out.println("\nDownloading blob to\n\t " + localPath + downloadFileName); blobClient.downloadToFile(localPath + downloadFileName); // Generate SAS String for blob user.. System.out.println("\nGenerate SAS String for blob user.."); GenerateSASstring(blobServiceClient, containerClient, blobClient); // Clean up System.out.println("\nPress the Enter word 'Delete' to begin clean up"); boolean isDelete = System.console().readLine().toLowerCase().trim().equals("delete"); if (isDelete) { System.out.println("Deleting blob container..."); containerClient.delete(); System.out.println("Deleting the local source and downloaded files..."); localFile.delete(); downloadedFile.delete(); } else { System.out.println("Skip to Clean up operation"); }System.out.println("Done"); }public static void GenerateSASstring(BlobServiceClient blobServiceClient, BlobContainerClient blobContainerClient, BlobClient blobClient) { /* * Generate an account sas. Other samples in this file will demonstrate how to * create a client with the sas token. */ // Configure the sas parameters. This is the minimal set.OffsetDateTime startTime = OffsetDateTime.now(); OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1); AccountSasService services = new AccountSasService().setBlobAccess(true); AccountSasResourceType resourceTypes = new AccountSasResourceType().setObject(true); SasProtocol protocol = SasProtocol.HTTPS_ONLY; SasIpRange sasIpRange = SasIpRange.parse("167.220.255.73"); // Generate the account sas. AccountSasPermission accountSasPermission = new AccountSasPermission().setReadPermission(true); AccountSasSignatureValues accountSasValues = new AccountSasSignatureValues(expiryTime, accountSasPermission, services, resourceTypes); accountSasValues.setStartTime(startTime); accountSasValues.setProtocol(protocol); accountSasValues.setSasIpRange(sasIpRange); String accountSasToken = blobServiceClient.generateAccountSas(accountSasValues); System.out.println("\nGenerate the account sas & url is :::: \n\t" + accountSasToken + "\n\t" + blobServiceClient.getAccountUrl() + "?" + accountSasToken); // Generate a sas using a container client BlobContainerSasPermission containerSasPermission = new BlobContainerSasPermission().setCreatePermission(true); BlobServiceSasSignatureValues serviceSasValues = new BlobServiceSasSignatureValues(expiryTime, containerSasPermission); serviceSasValues.setStartTime(startTime); serviceSasValues.setProtocol(protocol); serviceSasValues.setSasIpRange(sasIpRange); String containerSasToken = blobContainerClient.generateSas(serviceSasValues); System.out.println("\nGenerate the Container sas & url is :::: \n\t" + containerSasToken + "\n\t" + blobContainerClient.getBlobContainerUrl() + "?" + containerSasToken); // Generate a sas using a blob client BlobSasPermission blobSasPermission = new BlobSasPermission().setReadPermission(true); serviceSasValues = new BlobServiceSasSignatureValues(expiryTime, blobSasPermission); serviceSasValues.setStartTime(startTime); serviceSasValues.setProtocol(protocol); serviceSasValues.setSasIpRange(sasIpRange); String blobSasToken = blobClient.generateSas(serviceSasValues); System.out.println("\nGenerate the Blob sas & url is :::: \n\t" + blobSasToken + "\n\t" + blobClient.getBlobUrl() + "?" + blobSasToken); }}


参考资料
快速入门:使用 Java v12 SDK 管理 blob:https://docs.azure.cn/zh-cn/storage/blobs/storage-quickstart-blobs-java
Azure Storage Blob client library for Java:https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/storage/azure-storage-blob#generate-a-sas-token

示例下载:
【【Azure|【Azure 存储服务】代码版 Azure Storage Blob 生成 SAS (Shared Access Signature: 共享访问签名)】

    推荐阅读