使用令牌通过已注册的应用程序访问 Azure Blob

Posted

技术标签:

【中文标题】使用令牌通过已注册的应用程序访问 Azure Blob【英文标题】:Accessing Azure Blob via a Registered App Using Tokens 【发布时间】:2021-09-06 09:13:33 【问题描述】:

我是 Azure 的新手,正在努力让一个简单的演示工作。

我正在尝试编写一个访问 blob 的守护程序客户端。访问必须通过注册的应用程序,我想明确获取访问令牌。

作为热身,我编写了一个使用 blob api 访问 blob 的演示,这可以正常工作:

ClientCertificateCredential credentials = new ClientCertificateCredentialBuilder()
        .clientId("11518eab-7b5a-493c-8d12-27731fe51341")
        .tenantId("4b106bc5-7518-4f86-a259-f5726d124732")
        .pemCertificate("/home/william/cert/new/azure.pem")
        .build();
    
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
        .credential(credentials)
        .endpoint("https://wemsa.blob.core.windows.net/")
        .buildClient();
    
BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient("wemco");
     
blobContainerClient.getBlobClient("spiral.jpeg")
        .downloadToFile("/home/william/blob.jpeg");

上面的代码使用我注册的应用程序创建了一个BlobClient 来下载我的 blob 文件。这个工作的事实表明我的应用确实具有访问我的存储容器所需的角色。

我想创建第二个演示,做同样的事情,但我想明确获取访问令牌并使用它来授权对 blob api 的普通 http 请求。到目前为止,这是我制作的:

private static final String TENANT_ID = "4b106bc5-7518-4f86-a259-f5726d124732";
private static final String CLIENT_ID = "11518eab-7b5a-493c-8d12-27731fe51341";
private static final String AUTHORITY = "https://login.microsoftonline.com/" + TENANT_ID;
private static final Set<String> SCOPE = Collections.singleton("api://" + CLIENT_ID + "/.default");


InputStream pkcs12Cert = new FileInputStream("/home/william/cert/new/azure.p12");
String certPwd = "password123";
IClientCredential credential = ClientCredentialFactory.createFromCertificate(pkcs12Cert, certPwd);

ConfidentialClientApplication cca = ConfidentialClientApplication
        .builder(CLIENT_ID, credential).authority(AUTHORITY).build();

ClientCredentialParameters parameters = ClientCredentialParameters.builder(SCOPE).build();

IAuthenticationResult result = cca.acquireToken(parameters).join();
String token = result.accessToken();

URI uri = new URI("https://wemsa.blob.core.windows.net/wemco/spiral.jpeg");

HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
        .uri(uri)
        .header("Authorization", "Bearer " + token)
        .header("Date",           formatNow())
        .header("x-ms-version",  "2020-06-12")
        .GET()
        .build();

HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());

System.out.println(response.statusCode()); // 401 !!!

这使用与第一个演示相同的注册应用程序。调试告诉我它已成功获取访问令牌。但是,当我尝试使用它们时,我总是得到 401 响应。我曾希望由于第一个演示工作正常,第二个演示也能自动工作 - 但它没有。

我正在尝试做的事情是否可能? 我的第二个演示中的代码有问题吗? 在演示 2 运行之前,我是否需要在 Azure 中进行更多设置?一些 Azure 文档提到创建一个应用角色,我尝试过,但我不知道如何处理它。

有什么建议吗?


附加信息:这是我在 Azure 中所做的(接受所有内容的默认值):

创建存储帐户wemsawemsa 内创建容器 wemco 上传(一个小)文件“spiral.jpeg”到容器wemco 创建应用注册wemapp 将证书“azure.crt”上传到 wemapp

然后我回到容器 wemco 并且:

wemapp 授予角色“存储 Blob 数据贡献者”

这足以让演示 1 正常工作。

【问题讨论】:

【参考方案1】:

通过将范围(即请求的资源)更改为天蓝色存储来修复:

private static final Set<String> SCOPE = 
        Collections.singleton("https://storage.azure.com//.default");

进行此更改后,我可以使用原始帖子中的演示 2 代码下载我的 blob 文件。

【讨论】:

非常感谢您提供解决方案! 这个例子还适合你吗?我收到一条错误消息java.lang.IllegalArgumentException: restricted header name: "Date"

以上是关于使用令牌通过已注册的应用程序访问 Azure Blob的主要内容,如果未能解决你的问题,请参考以下文章

从 Powershell 获取 Azure Active Directory 访问令牌

我可以在不注册我的自动测试应用程序的情况下在 Azure 上获取访问令牌吗?

带有 AdlsClient 的 Azure MSI:访问令牌已过期

无法验证从 Azure AD 获得的访问令牌签名以保护 Web API

如何在 Azure Ad 中实现代流?

通过 Azure AD 验证不透明的访问令牌