问题描述
使用Java SDK来获取中国区 AI Search资源,使用如下代码:
package org.yourcompany.yourproject; import com.azure.core.credential.AccessToken; import com.azure.core.credential.TokenRequestContext; import com.azure.identity.AzureAuthorityHosts; import com.azure.identity.DefaultAzureCredential; import com.azure.identity.DefaultAzureCredentialBuilder; import com.azure.search.documents.SearchClient; import com.azure.search.documents.SearchClientBuilder; import com.azure.search.documents.models.SearchAudience; public class Javademo1 { public static void main(String[] args) { System.out.println("Hello World!"); String indexName = "xxxxx"; // Get the service endpoint from the environment String endpoint = "https://<your ai service name>.search.azure.cn"; String authorityHost = AzureAuthorityHosts.AZURE_CHINA; DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().authorityHost(authorityHost).build(); // Create a client SearchClient client = new SearchClientBuilder() .endpoint(endpoint) .indexName(indexName) .credential(credential) .buildClient(); long documentCount = client.getDocumentCount(); System.out.println("Document count: " + documentCount); } }
当运行时,会获取到如下错误:
com.microsoft.aad.msal4j.MsalServiceException: AADSTS500011: The resource principal named https://search.azure.com was not found in the tenant named XXXXXXXX. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
那么,应该如何修改代码,让它正常运行呢?
问题解答
因为JDK中,SearchClient 默认的认证是在Global 环境中,所以使用的默认地址为https://search.azure.com,而在中国区,则需要修改为https://search.azure.cn 。参考官方文档介绍,可以在构建SearchClientBuilder对象时设置 audience值为 SearchAudience.AZURE_CHINA。
修改后的代码为
String indexName = "xxxxx"; // Get the service endpoint from the environment String endpoint = "https://<your ai service name>.search.azure.cn"; String authorityHost = AzureAuthorityHosts.AZURE_CHINA; DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().authorityHost(authorityHost).build(); // Create a client SearchClient client = new SearchClientBuilder() .endpoint(endpoint) .indexName(indexName) .credential(credential) .audience(SearchAudience.AZURE_CHINA) //set the audience of your cloud .buildClient(); long documentCount = client.getDocumentCount();
如果想要单独获取AI Search资源的Token,可以使用如下代码:
String authorityHost = AzureAuthorityHosts.AZURE_CHINA; DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().authorityHost(authorityHost).build(); TokenRequestContext ctx = new TokenRequestContext() .addScopes("https://search.azure.cn/.default"); AccessToken accessToken = credential.getTokenSync(ctx); String token = accessToken.getToken(); System.out.println("Token: " + token);
获取到的Token,通过 https://jwt.io 解析后查看 aud的值就是 https://search.azure.cn
附件 : Dome的全部代码
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.yourcompany.yourproject</groupId> <artifactId>javademo1</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.release>17</maven.compiler.release> <exec.mainClass>org.yourcompany.yourproject.Javademo1</exec.mainClass> </properties> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.9.3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.9.3</version> <scope>test</scope> </dependency> <dependency> <groupId>com.azure</groupId> <artifactId>azure-search-documents</artifactId> <version>11.8.0</version> </dependency> <dependency> <groupId>com.azure</groupId> <artifactId>azure-identity</artifactId> <version>1.16.3</version> </dependency> </dependencies> </project>
Javademo1.java
/* * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license */ package org.yourcompany.yourproject; import com.azure.core.credential.AccessToken; import com.azure.core.credential.TokenRequestContext; import com.azure.identity.AzureAuthorityHosts; import com.azure.identity.DefaultAzureCredential; import com.azure.identity.DefaultAzureCredentialBuilder; import com.azure.search.documents.SearchClient; import com.azure.search.documents.SearchClientBuilder; import com.azure.search.documents.models.SearchAudience; public class Javademo1 { public static void main(String[] args) { System.out.println("Hello World!"); String indexName = "xxxxx"; // Get the service endpoint from the environment String endpoint = "https://<your ai service name>.search.azure.cn"; String authorityHost = AzureAuthorityHosts.AZURE_CHINA; DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().authorityHost(authorityHost).build(); TokenRequestContext ctx = new TokenRequestContext() .addScopes("https://search.azure.cn/.default"); AccessToken accessToken = credential.getTokenSync(ctx); String token = accessToken.getToken(); System.out.println("Token: " + token); // Create a client SearchClient client = new SearchClientBuilder() .endpoint(endpoint) .indexName(indexName) .credential(credential) .audience(SearchAudience.AZURE_CHINA) //set the audience of your cloud .buildClient(); long documentCount = client.getDocumentCount(); System.out.println("Document count: " + documentCount); System.out.println("Search client created: " + client.getEndpoint()); } }
参考资料
Create a client using Microsoft Entra ID authentication : https://learn.microsoft.com/zh-cn/java/api/overview/azure/search-documents-readme?view=azure-java-stable#create-a-client-using-microsoft-entra-id-authentication
Authenticate in a National Cloud : https://learn.microsoft.com/zh-cn/java/api/com.azure.search.documents?view=azure-java-stable
[END]
当在复杂的环境中面临问题,格物之道需:浊而静之徐清,安以动之徐生。 云中,恰是如此!