我尝试通过oauth2连接到Google-Analytics-API身份验证
当我运行以下代码时,身份验证似乎可以正常工作,但随后我得到:
"javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target"
当来到这一行:
Accounts accounts = analytics.management().accounts().list().execute();
我已将https://www.googleapis.com/证书添加到
jre7-keystore
,但这无济于事有人对我能做什么有想法吗?有没有办法只接受所有证书?
/*
* Copyright (c) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.DataStoreFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.analytics.Analytics;
import com.google.api.services.analytics.AnalyticsScopes;
import com.google.api.services.analytics.model.Accounts;
import com.google.api.services.analytics.model.GaData;
import com.google.api.services.analytics.model.GaData.ColumnHeaders;
import com.google.api.services.analytics.model.Profiles;
import com.google.api.services.analytics.model.Webproperties;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* This is a basic hello world sample for the Google Analytics API. It is designed to run from the
* command line and will prompt a user to grant access to their data. Once complete, the sample will
* traverse the Management API hierarchy by going through the authorized user's first account, first
* web property, and finally the first profile and retrieve the first profile id. This ID is then
* used with the Core Reporting API to retrieve the top 25 organic search terms.
*
* @author [email protected]
*/
public class HelloAnalyticsApiSample {
/**
* Be sure to specify the name of your application. If the application name is {@code null} or
* blank, the application will log a warning. Suggested format is "MyCompany-ProductName/1.0".
*/
private static final String APPLICATION_NAME = "Neckermann-Analytics/1.0";
/** Directory to store user credentials. */
private static final java.io.File DATA_STORE_DIR =
// new java.io.File(System.getProperty("user.home"), ".store/analytics_sample");
new java.io.File("G:/Programm Daten/GA", ".store/analytics_sample");
/**
* Global instance of the {@link DataStoreFactory}. The best practice is to make it a single
* globally shared instance across your application.
*/
private static FileDataStoreFactory dataStoreFactory;
/** Global instance of the HTTP transport. */
private static HttpTransport httpTransport;
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final String CLIENT_ID = "xxx";
private static final String CLIENT_SECRET = "xxx";
/**
* Main demo. This first initializes an analytics service object. It then uses the Google
* Analytics Management API to get the first profile ID for the authorized user. It then uses the
* Core Reporting API to retrieve the top 25 organic search terms. Finally the results are printed
* to the screen. If an API error occurs, it is printed here.
*
* @param args command line args.
*/
public static void main(String[] args) {
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
Analytics analytics = initializeAnalytics();
String profileId = getFirstProfileId(analytics);
if (profileId == null) {
System.err.println("No profiles found.");
} else {
GaData gaData = executeDataQuery(analytics, profileId);
printGaData(gaData);
}
} catch (GoogleJsonResponseException e) {
System.err.println("There was a service error: " + e.getDetails().getCode() + " : "
+ e.getDetails().getMessage());
} catch (Throwable t) {
t.printStackTrace();
}
}
/** Authorizes the installed application to access user's protected data. */
private static Credential authorize() throws Exception {
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, CLIENT_ID,CLIENT_SECRET,
Collections.singleton(AnalyticsScopes.ANALYTICS_READONLY)).setDataStoreFactory(
dataStoreFactory).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
}
/**
* Performs all necessary setup steps for running requests against the API.
*
* @return An initialized Analytics service object.
*
* @throws Exception if an issue occurs with OAuth2Native authorize.
*/
private static Analytics initializeAnalytics() throws Exception {
// Authorization.
Credential credential = authorize();
// Set up and return Google Analytics API client.
return new Analytics.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName(
APPLICATION_NAME).build();
}
/**
* Returns the first profile id by traversing the Google Analytics Management API. This makes 3
* queries, first to the accounts collection, then to the web properties collection, and finally
* to the profiles collection. In each request the first ID of the first entity is retrieved and
* used in the query for the next collection in the hierarchy.
*
* @param analytics the analytics service object used to access the API.
* @return the profile ID of the user's first account, web property, and profile.
* @throws IOException if the API encounters an error.
*/
private static String getFirstProfileId(Analytics analytics) throws IOException {
String profileId = null;
// Query accounts collection.
Accounts accounts = analytics.management().accounts().list().execute();
if (accounts.getItems().isEmpty()) {
System.err.println("No accounts found");
} else {
String firstAccountId = accounts.getItems().get(0).getId();
// Query webproperties collection.
Webproperties webproperties =
analytics.management().webproperties().list(firstAccountId).execute();
if (webproperties.getItems().isEmpty()) {
System.err.println("No Webproperties found");
} else {
String firstWebpropertyId = webproperties.getItems().get(0).getId();
// Query profiles collection.
Profiles profiles =
analytics.management().profiles().list(firstAccountId, firstWebpropertyId).execute();
if (profiles.getItems().isEmpty()) {
System.err.println("No profiles found");
} else {
profileId = profiles.getItems().get(0).getId();
}
}
}
return profileId;
}
/**
* Returns the top 25 organic search keywords and traffic source by visits. The Core Reporting API
* is used to retrieve this data.
*
* @param analytics the analytics service object used to access the API.
* @param profileId the profile ID from which to retrieve data.
* @return the response from the API.
* @throws IOException tf an API error occured.
*/
private static GaData executeDataQuery(Analytics analytics, String profileId) throws IOException {
return analytics.data().ga().get("ga:" + profileId, // Table Id. ga: + profile id.
"2012-01-01", // Start date.
"2012-01-14", // End date.
"ga:visits") // Metrics.
.setDimensions("ga:source,ga:keyword")
.setSort("-ga:visits,ga:source")
.setFilters("ga:medium==organic")
.setMaxResults(25)
.execute();
}
/**
* Prints the output from the Core Reporting API. The profile name is printed along with each
* column name and all the data in the rows.
*
* @param results data returned from the Core Reporting API.
*/
private static void printGaData(GaData results) {
System.out.println(
"printing results for profile: " + results.getProfileInfo().getProfileName());
if (results.getRows() == null || results.getRows().isEmpty()) {
System.out.println("No results Found.");
} else {
// Print column headers.
for (ColumnHeaders header : results.getColumnHeaders()) {
System.out.printf("%30s", header.getName());
}
System.out.println();
// Print actual data.
for (List<String> row : results.getRows()) {
for (String column : row) {
System.out.printf("%30s", column);
}
System.out.println();
}
System.out.println();
}
}
}
这就是我得到的异常的完整堆栈跟踪:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Unknown Source)
at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source)
at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:93)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:965)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at HelloAnalyticsApiSample.getFirstProfileId(HelloAnalyticsApiSample.java:194)
at HelloAnalyticsApiSample.main(HelloAnalyticsApiSample.java:123)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
... 18 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
... 24 more
最佳答案
毕竟问题出在我所工作的公司的防火墙上。防火墙以某种方式更改了http-header。将* .googleapis.com列入白名单后,它可以正常工作。
关于java - 连接到Google Analytics API时Java中的SSL异常(exception),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27601467/