无法使用 MSAL4J 从 Azure AD 获取访问令牌

Not able to get access token from azure AD using MSAL4J

我正在尝试访问图表 api。我正在使用 MSAL4J 访问 graph api。但是即使我没有使用我的 vpn,我也会收到 com.microsoft.aad.msal4j.MsalClientException: java.net.SocketTimeoutException: connect timed out

我正在学习 this 教程。我已按照其中提到的所有步骤进行操作。

这里是堆栈跟踪:

Exception in thread "main" java.util.concurrent.ExecutionException: com.microsoft.aad.msal4j.MsalClientException: java.net.SocketTimeoutException: connect timed out at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357) at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895) at ClientCredentialGrant.getAccessTokenByClientCredentialGrant(ClientCredentialGrant.java:78) at ClientCredentialGrant.main(ClientCredentialGrant.java:36) Caused by: com.microsoft.aad.msal4j.MsalClientException: java.net.SocketTimeoutException: connect timed out at com.microsoft.aad.msal4j.HttpHelper.executeHttpRequest(HttpHelper.java:53) at com.microsoft.aad.msal4j.AadInstanceDiscoveryProvider.executeRequest(AadInstanceDiscoveryProvider.java:218) at com.microsoft.aad.msal4j.AadInstanceDiscoveryProvider.sendInstanceDiscoveryRequest(AadInstanceDiscoveryProvider.java:172) at com.microsoft.aad.msal4j.AadInstanceDiscoveryProvider.doInstanceDiscoveryAndCache(AadInstanceDiscoveryProvider.java:271) at com.microsoft.aad.msal4j.AadInstanceDiscoveryProvider.getMetadataEntry(AadInstanceDiscoveryProvider.java:56) at com.microsoft.aad.msal4j.AuthenticationResultSupplier.getAuthorityWithPrefNetworkHost(AuthenticationResultSupplier.java:32) at com.microsoft.aad.msal4j.AcquireTokenByAuthorizationGrantSupplier.execute(AcquireTokenByAuthorizationGrantSupplier.java:59) at com.microsoft.aad.msal4j.AcquireTokenByClientCredentialSupplier.acquireTokenByClientCredential(AcquireTokenByClientCredentialSupplier.java:63) at com.microsoft.aad.msal4j.AcquireTokenByClientCredentialSupplier.execute(AcquireTokenByClientCredentialSupplier.java:49) at com.microsoft.aad.msal4j.AuthenticationResultSupplier.get(AuthenticationResultSupplier.java:59) at com.microsoft.aad.msal4j.AuthenticationResultSupplier.get(AuthenticationResultSupplier.java:17) at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590) at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582) at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289) at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056) at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692) at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) Caused by: java.net.SocketTimeoutException: connect timed out at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:673) at sun.net.NetworkClient.doConnect(NetworkClient.java:175) at sun.net.www.http.HttpClient.openServer(HttpClient.java:463) at sun.net.www.http.HttpClient.openServer(HttpClient.java:558) at sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:264) at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:367) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:191) at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1138) at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1032) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:177) at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1546) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474) at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338) at com.microsoft.aad.msal4j.DefaultHttpClient.readResponseFromConnection(DefaultHttpClient.java:107) at com.microsoft.aad.msal4j.DefaultHttpClient.executeHttpGet(DefaultHttpClient.java:47) at com.microsoft.aad.msal4j.DefaultHttpClient.send(DefaultHttpClient.java:35) at com.microsoft.aad.msal4j.HttpHelper.executeHttpRequestWithRetries(HttpHelper.java:96) at com.microsoft.aad.msal4j.HttpHelper.executeHttpRequest(HttpHelper.java:49) ... 16 more

任何帮助将不胜感激。

我终于明白了。并写下这个答案,希望它能对某人有所帮助。 com.microsoft.aad.msal4j.MsalClientException: java.net.SocketTimeoutException: connect timed out 由于代理问题发生此异常。

我的系统位于代理后面,因此无法连接 microsoftonline 服务器。

我有两种方法从 azure AD 获取 access_token

第一种方法 使用由 AZURE AD

提供的 REST API
public String getAccessToken() throws UnsupportedOperationException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("your_proxy_address", your_proxy_port));
        OkHttpClient client = new OkHttpClient.Builder().proxy(proxy).build();

        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        RequestBody body = RequestBody.create(
                "grant_type=client_credentials&client_id=your_client_id&scope=https://graph.microsoft.com/.default&client_secret=your_client_secret",
                mediaType);
        Request request = new Request.Builder()
                .url("https://login.microsoftonline.com/your tenent id/oauth2/v2.0/token")
                .method("POST", body).addHeader("Content-Type", "application/x-www-form-urlencoded").build();

        Response response = client.newCall(request).execute();
        // String token = response.body().string();
        return mapper.readTree(response.body().string()).get("access_token").asText();
    }

您可以使用此方法获得access_token。另一种方法是使用 MSAL4J 库。 第二种方法

首先构建客户端object

private static void BuildConfidentialClientObject() throws Exception {

        Proxy proxy = AuthProvider.getInstance().getProxy();

        app = ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(secret))
                .proxy(proxy).authority(authority).build();
    }

然后得到access_token

private static IAuthenticationResult getAccessTokenByClientCredentialGrant() throws Exception {

        ClientCredentialParameters clientCredentialParam = ClientCredentialParameters
                .builder(Collections.singleton(scope)).build();

        CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
        return future.join();

    }

现在您可以使用此 access_token 访问 graph APIs 并完成您的任务。

PS: 我正在使用 demon 方法来完成我的任务。有不同的方法可以满足您的要求。

你可以看看here认证方式参考