java - Azure RateCard "AuthenticationFailed""
问题描述
我想通过带有 Java 应用程序的 Billing Api 获得 Azure RateCard。首先,我创建了一个可以正常工作的 AccessToken。但是当我想使用这个 AccessToken 来获取 RateCard 时,我得到了一个身份验证错误。这是我的java代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class TestingAzure {
public static String getAccessToken(String tenantId, String clientId, String clientSecret)
throws MalformedURLException, IOException {
String endpoint = String.format("https://login.microsoftonline.com/%s/oauth2/token", tenantId);
String postBody = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s&resource=%s",
clientId, clientSecret, "https://management.azure.com/");
HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
conn.getOutputStream().write(postBody.getBytes());
conn.connect();
// If you want to see the response content, please use the commented code below.
// BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// StringBuilder builder = new StringBuilder();
// String line = null;
// while ((line = reader.readLine()) != null) {
// builder.append(line);
// }
// reader.close();
// System.out.println(builder.toString());
// The output for access token is {"token_type":"Bearer","expires_in":"3600","ext_expires_in":"3600","expires_on":"1550660092","not_before":"1550656192","resource":"https://management.azure.com/","access_token":"eyJ0eXAiOiJKV1QiL...."}
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(conn.getInputStream());
String accessToken = null;
while (parser.nextToken() != JsonToken.END_OBJECT) {
String name = parser.getCurrentName();
if ("access_token".equals(name)) {
parser.nextToken();
accessToken = parser.getText();
}
}
return accessToken;
}
public static String getRateCard(String subscriptionId, String apiVersion, String offerId, String currency,
String locale, String region, String accessToken) throws MalformedURLException, IOException {
String endpoint = String.format(
"https://management.azure.com/subscriptions/%s/providers/Microsoft.Commerce/RateCard?api-version=%s&$filter=OfferDurableId eq '%s' and Currency eq '%s' and Locale eq '%s' and RegionInfo eq '%s'",
subscriptionId, apiVersion, offerId, currency, locale, region).replaceAll(" ", "%20");
HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
conn.setRequestMethod("GET");
conn.addRequestProperty("Authorization", "Bearer " + accessToken);
conn.addRequestProperty("Content-Type", "application/json");
conn.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
reader.close();
return builder.toString();
}
public static void main(String[] args) throws MalformedURLException, IOException {
String tenantId = "*****";
String clientId = "*****";
String clientSecret = "*****";
clientSecret=java.net.URLEncoder.encode(clientSecret,"UTF-8");
System.out.println(clientSecret);
String accessToken = getAccessToken(tenantId, clientId, clientSecret);
System.out.println(accessToken);
String subscriptionId = "*****";
String apiVersion = "2015-06-01-preview";
String offerId = "****";
String currency = "EUR";
String locale = "de-DE";
String region = "DE";
String rateCardResp = getRateCard(subscriptionId, apiVersion, offerId, currency, locale, region, accessToken);
System.out.println(rateCardResp);
}
}
在 Eclipse 中,错误是:
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 403 for URL: https://management.azure.com/subscriptions/*subscriptionID*/providers/Microsoft.Commerce/RateCard?api-version=2015-06-01-preview&$filter=OfferDurableId%20eq%20'MS-AZR-0017P'%20and%20Currency%20eq%20'EUR'%20and%20Locale%20eq%20'de-DE'%20and%20RegionInfo%20eq%20'DE'
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
at com.nttdata.altemista.TestingAzure.getRateCard(TestingAzure.java:60)
at com.nttdata.altemista.TestingAzure.main(TestingAzure.java:84)
当我搜索 URL 时,我收到以下消息:
{"error":{"code":"AuthenticationFailed","message":"Fehler bei der Authentifizierung. Der Authorization-Header fehlt."}}
实际上,我在处理此订阅时担任了最高角色。我不知道我可以尝试什么。
解决方案
在您的示例中,您是否为您的服务主体授予了足够的权限,即访问 Windows Azure 服务管理 API 的权限。
这是一个很好的例子,如果你想在 Java 中访问管理资源,如何在 Azure AD 中配置应用程序
或者,您可以按照以下方式配置本机应用程序以使用 Azure Rate card Api 第 1 步:在您的 AAD 租户中配置本机客户端应用程序
在您可以运行示例应用程序之前,您需要允许它访问您的 AAD 租户以进行身份验证和授权以访问计费 API。如果您已经配置了一个想要使用的 Native Client Application(并且它已根据以下步骤进行配置),您可以跳转到第 2 步。
要配置新的 AAD 应用程序:
使用已在信任您的 AAD 租户的订阅上授予服务管理员/共同管理员访问权限并在 AAD 租户中授予全局管理员访问权限的凭据登录到 Azure 门户。有关管理服务管理员和共同管理员的详细信息,请参阅管理帐户、订阅和管理角色。
选择您要使用的 AAD 租户,然后转到“应用程序”页面。
从那里,您可以使用“添加”功能来“添加我的组织正在开发的新应用程序”。
为新应用程序提供一个名称(即:ConsoleApp-Billing-RateCard 或类似名称)。
确保选择“Native Client Application”类型,然后为“Redirect URI”指定一个有效的 URL(在本示例中可以是http://localhost/ ),然后单击复选标记保存。
添加新应用程序后,在应用程序列表中再次选择它并单击“配置”,以确保示例应用程序将有权访问 Windows Azure 服务管理 API,该权限用于保护计费 API。
向下滚动到新创建的应用程序配置页面的“对其他应用程序的权限”部分。然后单击“添加应用程序”按钮,选择“Windows Azure 服务管理”行,然后单击复选标记保存。保存后,将鼠标悬停在“Windows Azure服务管理”行右侧的“委派权限”区域,点击“委派权限”下拉列表,选择“访问Azure服务管理(预览版)”选项,点击“再次保存”。
注意:默认情况下启用“Windows Azure Active Directory”权限“启用登录和读取用户配置文件”。它允许用户使用他们的组织帐户登录到应用程序,使应用程序能够读取登录用户的个人资料,例如他们的电子邮件地址和联系信息。这是一种委托权限,使用户能够在继续之前同意。请参阅添加、更新和删除应用程序以更深入地了解如何配置 Azure AD 租户以使应用程序能够访问您的租户。
- 当您在此页面上时,还要记下/复制“客户端 ID”GUID 和“重定向 URI”,
因为您将在下面的第 3 步中使用它们。您还需要您的 Azure 订阅 ID 和 AAD 租户域名,您可以从管理门户的“设置”页面复制这两者。
注意:- 如果您想使用 grant_type="Client_credential" 并使用客户端 ID 和 client_secret,请确保您在订阅中至少具有 admin/co admin 角色,并且您的应用程序具有上述足够的权限。
推荐阅读
- html - 如何在 Haml 中禁用编辑输入
- javascript - 将 blob 转换为 wav 文件
- google-app-engine - 谷歌云CDN,使用apache benchmark的性能测试
- apify - 如何使用 API 为特定的 Task 或 Actor 创建 Apify Webhook
- rapids - 在使用 rapids.ai 时如何确定内存统计数据?
- ruby-on-rails - ActiveRecord 获取具有一组特定相关模型的所有模型(AND 不是 OR)
- html - 将 LaTeX 转换为 HTML
- c++ - 除以 str.length() 没有显示任何内容
- powershell - PowerCLI 有一个隐藏的 vc 别名,我不知道它来自哪里以及是否有更多类似的
- swift - 即使在睡眠期间也能在 macOS 上继续播放声音