通过OAuth2为简单API访问生成和接收GA API密钥

时间:2013-10-14 14:38:33

标签: oauth-2.0 google-analytics-api google-oauth google-api-java-client kettle

以下是故事:

我使用Pentaho Kettle通过简单API访问从Google Analytics查询网络统计信息。对于此请求,我需要API密钥。现在这个API密钥时不时变为无效(我不确定rythm是什么)然后请求失败当然。所以我想生成一个新的,接收它并使其可用于ETL作业及其GA步骤。

我的计划是通过User Defined Java Classgoogle-api-java-client在一个或多个“Service Account”步骤中嵌入Java来实现此目的。 Kettle作业生成一个新的API密钥,接收它并通过字段或直接作为参数提供API密钥。

但主要是我对所描述的用例的一般Java解决方案感兴趣。如果有人有一个更好的解决方案,但我提到这些细节主要是为了将问题放到一个背景中。

问题:如何为Google Analytics简单API访问生成新的API密钥,并通过OAuth2使用google-api-java-client接收它,而无需用户交互(完全自动化)?< / p>

Bounty :我很感激答案提供Java程序或详细的API调用序列。该程序的输出是一个适用于简单API访问的功能API密钥。鉴于所涉及的预期工作,我选择了尽可能高的赏金。


我注册了一个服务帐户,所以我有以下ID和有限公司:

  • 客户ID
    • 123.apps.googleusercontent.com
  • 电子邮件地址
    • 123@developer.gserviceaccount.com
  • 公钥指纹
    • abcxxx
  • 的client_secrets.json
    • {...}
  • 私钥
    • abcxxx-privatekey.p12

的client_secrets.json:

{"web":{
  "auth_uri":            "https://accounts.google.com/o/oauth2/auth",
  "token_uri":           "https://accounts.google.com/o/oauth2/token",
  "client_email":        "123@developer.gserviceaccount.com",
  "client_x509_cert_url":"https://www.../123@developer.gserviceaccount.com",
  "client_id":           "123.apps.googleusercontent.com",
  "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"
}}

2 个答案:

答案 0 :(得分:2)

代码之前的一些事情:

  1. 从技术上讲,如果您使用OAuth 2.0进行身份验证,那么Simple API访问根本不适用。因此您无需担心API密钥。 Pentaho的说明是旧的,除非您使用非OAuth 2.0身份验证机制(这不是您应该做的),否则不适用

  2. 您最想要使用的是用于身份验证的服务帐户,不需要任何人工干预。

  3. 注册应用

    如果您尚未使用Google Cloud Console注册申请,请在云端控制台中设置项目和应用程序。系统将指导您完成选择或创建项目以及注册新应用程序的过程,并自动为您激活API。

    如果您已使用Cloud Console注册了应用程序,请改为使用此过程:

    转到Google Cloud Console。 选择一个项目。 在左侧边栏中,选择API&amp; AUTH。在显示的API列表中,确保将Analytics API状态设置为ON。 在左侧边栏中,选择已注册的应用。 选择一个应用程序 在任何一种情况下,您都会在应用程序的凭据页面上结束。

    要设置服务帐户,请展开“证书”部分。然后选择Generate Certificate。 (如果您已有证书,则可以通过选择“生成新密钥”来添加新密钥。)将出现一个对话框。选择下载私钥以继续。下载完成后,选择查看公钥。

    下载文件并关闭对话框后,您将能够获得服务帐户的电子邮件地址。

    下载用于分析的Java客户端库

    访问https://developers.google.com/api-client-library/java/apis/analytics/v3

    转到底部的将库添加到您的项目部分,然后下载适用于Java的Google AnalyticsAPI v3客户端库。

    将服务帐户电子邮件添加到GA帐户

    将服务帐户电子邮件添加到您要通过API访问的Google Analytics帐户。

    获取访问次数的Java应用示例

    以下代码段适用于Core Reporting API。它使用服务帐户进行身份验证。然后,它会检索Google Analytics配置文件的访问次数并输出该号码。

    要使用此功能,您显然应该替换服务帐户电子邮件和私钥文件的路径。您还需要从libs文件夹导入用于分析的Java客户端和相关的JARS。

    另请参阅Google Analytics Core Reporting API docs了解如何使用维度和指标,细分,过滤器等查询API。

    您应该可以对其进行自定义,以便与您的应用程序一起使用。

    import java.io.IOException;
    import java.security.GeneralSecurityException;
    import java.util.HashSet;
    import java.util.Set;
    
    import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
    import com.google.api.client.http.HttpTransport;
    import com.google.api.client.http.javanet.NetHttpTransport;
    import com.google.api.client.json.jackson2.JacksonFactory;
    import com.google.api.services.analytics.Analytics;
    import com.google.api.services.analytics.AnalyticsScopes;
    import com.google.api.services.analytics.model.GaData;
    
    public class AnalyticsSample  {
    
        private static final String APPLICATION_NAME = "APP_NAME";
    
        private static final String SERVICE_ACCOUNT_EMAIL = "<YOUR_SERVICE_ACCOUNT_EMAIL>@developer.gserviceaccount.com";
    
        /** Path to the Service Account's Private Key file */
        private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/path/to/-privatekey.p12";
    
        private static Analytics service;
    
        public static Analytics getAnalyticsService() throws GeneralSecurityException, IOException {
            Set<String> scopes = new HashSet<String>();
            scopes.add(AnalyticsScopes.ANALYTICS_READONLY); // You can set other scopes if needed 
    
            HttpTransport httpTransport = new NetHttpTransport();
            JacksonFactory jsonFactory = new JacksonFactory();
            GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(jsonFactory)
                .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
                .setServiceAccountScopes(scopes)
                .setServiceAccountPrivateKeyFromP12File(
                        new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
                .build();
            Analytics service = new Analytics.Builder(httpTransport, jsonFactory, null)
                .setHttpRequestInitializer(credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
            return service;
        }
    
         public static void main(String[] args) {
             try {
                 service = getAnalyticsService();
                 GaData result = service.data().ga().get(
                         "ga:<YOUR PROFILE ID>",
                         "2013-10-16", // Start date
                         "2013-10-17", // End Date
                         "ga:visits").execute();  // Add Dimensions and metrics
    
                 System.out.println(result.getRows().get(0).get(0)); // Just an example of output
    
             } catch (IOException e) {
                 System.err.println(e.getMessage());
             } catch (GeneralSecurityException e) {
                 System.err.println(e.getMessage());
             } catch (Throwable t) {
                 t.printStackTrace();
             }
             System.exit(1);
         }
    
    }
    

答案 1 :(得分:1)

我不是Java人,但我正在做的就是你要求使用Go和Google API。我可以给你一个关于这个过程的概述,希望这有助于/向你发送正确的方向吗? :)

概述:

  • 从您在Google云端控制台中注册的应用下载证书
  • 将证书从PCS12编码转换为PEM
  • 使用该密钥制作JWT(JSON网络令牌),以及电子邮件地址(foobarbazxxxxetc@developer.gserviceaccount.com一个)以及您要使用的API范围。
  • 将具有相应权限的相同电子邮件地址添加到您要使用的分析帐户
  • 使用JWT获取oauth令牌
  • 创建分析服务,使用oauth令牌进行身份验证
  • 现在您可以与核心报告API进行对话

编辑:不需要钥匙再生。令牌持续1小时,无法刷新。但这并不重要,因为下次使用密钥进行身份验证时,您将获得一个持续一小时的新令牌。

编辑2:我正在使用docs / pre-reqs / comments包括干净的编译Go代码。希望这会有所帮助!

package main

// overview of crqs.go:
// this example app and supporting documentation enables you to query analytics data via the Core Reporting API in a completely headless manner, with
// no "popup" or user intervention required. it doesn't "handle" the returned data very well, as that will depend on what metrics/dimensions your
// query has. better handling of this is left as an exercise for the reader. :) follow the pre-reqs, change the ga* consts specific to your own app,
// and you should be good to go. uses google-api-go-client, analytics/v3, oauth, and oauth/jwt which you can download and install from
// https://code.google.com/p/goauth2/ and http://code.google.com/p/google-api-go-client/

// docs/pre-reqs:
// 1. create a Project within the Google Cloud Console (https://cloud.google.com/console#/project)
// 2. within that Project, ensure you've turned on the Analytics API (APIs & Auth --> Analytics --> On)
// 3. within that Project, create an application of type "Web Application" (APIs & Auth --> Registered Apps)
// 4. click on the application name. expand the "Certificate" section. you will see that the email/public keys
//    have not been generated. click "Generate". download the private key (.p12 file). also, note the private key password, and
//    the email address, you will need these later. you will set the string const gaServiceAcctEmail to this email address.
// 5. download the JSON file, too. you will set the const gaServiceAcctSecretsFile to the location of this file.
// 6. now we need to convert the .p12 key to a PEM key. in a unix shell:
//    $ openssl pkcs12 -in privatekeyfilename.p12 -nodes -nocerts > privatekeyfilename.pem
//    it will ask you for the Import password. enter the private key password you were given in step 4. you should see
//    "MAC verified OK", and you will have the PEM key. you will set the const gaServiceAcctPEMKey to the location of this file.
// 7. goto Google Analytics. in Admin section specific to the GA account/property you wish to query, give Read & Analyze permissions to the
//    email address you were given in step 4.
// 8. now we need the Table ID of the GA account/property mentioned in step 7. login to the Google Analytics Query Explorer 2 at
//    http://ga-dev-tools.appspot.com/explorer/ then select the appropriate account/property/profile in the dropdown menus. you will see
//    the Table ID in the "*ids" box. it looks like "ga:1234556". you will set the string const gaTableID to this value.
// 9. that should be all you need to do! compile and "go".

// example runs:
// 1. shows total pageview count for all URLs (starting at default date october 1st through today).
// $ ./crqs
// gaStartDate=2013-10-01, gaEndDate=2013-10-18
// gaMetrics=ga:pageviews
// gaFilter=ga:pagePath=~^/
// len(gaData.Rows)=1, TotalResults=1
// row=0 [25020179]
//
// 2. shows unique pageview count per URL for top 5 URLs starting in "/movies" (starting at default date october 1st through today),
// in descending order.
// $ ./crqs -m=ga:uniquePageviews -d=ga:pagePath -s=-ga:uniquePageviews -f=ga:pagePath=~^/movies -x=5
// gaStartDate=2013-10-01, gaEndDate=2013-10-18
// gaMetrics=ga:uniquePageviews
// gaDimensions=ga:dimensions=ga:pagePath
// gaSortOrder=ga:sort=-ga:uniquePageviews
// gaFilter=ga:pagePath=~^/movie
// len(gaData.Rows)=5, TotalResults=10553
// row=0 [/movies/foo 1005697]
// row=1 [/movies/bar 372121]
// row=2 [/movies/baz 312901]
// row=3 [/movies/qux 248761]
// row=4 [/movies/xyzzy 227286]
//
// 3. shows unique pageview count per URL for top 5 URLs from Aug 1 --> Sep 1, in descending order.
// $ ./crqs -sd=2013-08-01 -ed=2013-09-01 -m=ga:uniquePageviews -d=ga:pagePath -s=-ga:uniquePageviews -x=5
// gaStartDate=2013-08-01, gaEndDate=2013-09-01
// gaMetrics=ga:uniquePageviews
// gaDimensions=ga:dimensions=ga:pagePath
// gaSortOrder=ga:sort=-ga:uniquePageviews
// len(gaData.Rows)=5, TotalResults=159023
// row=0 [/ 4280168]
// row=1 [/foo 2504679]
// row=2 [/bar 1177822]
// row=3 [/baz 755705]
// row=4 [/xyzzy 739513]

import (
    "code.google.com/p/goauth2/oauth"
    "code.google.com/p/goauth2/oauth/jwt"
    "code.google.com/p/google-api-go-client/analytics/v3"
    "encoding/json"
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "time"
)

// constants
const (
    // don't change these
    dateLayout string = "2006-01-02" // date format that Core Reporting API requires
    // change these! add in your own app and analytics-property-specific values
    gaServiceAcctEmail       string = "your-applications-email-address@developer.gserviceaccount.com"           // email address of registered application
    gaServiceAcctSecretsFile string = "/path/to/client_secret_your-application.apps.googleusercontent.com.json" // registered application JSON file downloaded from Google Cloud Console
    gaServiceAcctPEMKey      string = "/path/to/your-applications-converted-privatekey.pem"                     // private key (PEM format) of registered application
    gaScope                  string = "https://www.googleapis.com/auth/analytics.readonly"                      // oauth 2 scope information for Core Reporting API
    gaTableID                string = "ga:12345678"                                                             // namespaced profile ID of the analytics account/property/profile from which to request data
)

// globals
var (
    // vars for the runtime flags
    gaDimensions string
    gaEndDate    string
    gaFilter     string
    gaMetrics    string
    gaMaxResults int64
    gaSortOrder  string
    help         bool
    gaStartDate  string
)

// types

// struct to read the registered application's JSON secretsfile into
type GAServiceAcctSecretsConfig struct {
    ClientEmail  string   `json:"client_email"`
    ClientId     string   `json:"client_id"`
    ClientSecret string   `json:"client_secret"`
    RedirectURIs []string `json:"redirect_uris"`
    Scope        string
    AuthURI      string `json:"auth_uri"`
    TokenURI     string `json:"token_uri"`
}

// func: init()

// initialisation function for the command line flags/options.
func init() {
    flag.BoolVar(&help, "h", false, "Show all command line arguments.")
    flag.StringVar(&gaDimensions, "d", "", "GA query dimensions")
    flag.StringVar(&gaEndDate, "ed", "", "GA query end date")
    flag.StringVar(&gaFilter, "f", "", "GA filter to apply")
    flag.Int64Var(&gaMaxResults, "x", 10000, "GA maximum # of results to return (default: 10000)")
    flag.StringVar(&gaMetrics, "m", "ga:pageviews", "GA metrics you want to query (default: ga:pageviews)")
    flag.StringVar(&gaSortOrder, "s", "", "GA query reply sort order")
    flag.StringVar(&gaStartDate, "sd", "2013-10-01", "GA query start date (default: 2013-10-01)")
}

// func: readConfig()

// reads in the registered application's JSON secretsfile and crafts an oauth.Config which
// it returns to the calling func. exits hard if either the JSON secretsfile load fails,
// or if the unmarshal fails.
func readGAServiceAcctSecretsConfig() *oauth.Config {
    configfile := new(GAServiceAcctSecretsConfig)
    data, err := ioutil.ReadFile(gaServiceAcctSecretsFile)
    if err != nil {
        log.Fatal("error reading GA Service Account secret JSON file -", err)
    }
    err = json.Unmarshal(data, &configfile)
    if err != nil {
        log.Fatal("error unmarshalling GA Service Account secret JSON file -", err)
    }
    return &oauth.Config{
        ClientId:     configfile.ClientId,
        ClientSecret: configfile.ClientSecret,
        Scope:        gaScope,
        AuthURL:      configfile.AuthURI,
        TokenURL:     configfile.TokenURI,
    }
} //

// func: main()

// the main function. duh.
func main() {
    // grok the command line args
    flag.Usage = usage
    flag.Parse()
    if help {
        flag.Usage()
    }
    // read in the registered application's JSON secretsfile and get an oauth.Config in return.
    oauthConfig := readGAServiceAcctSecretsConfig()
    // read in the registered applications private PEM key.
    pemKey, err := ioutil.ReadFile(gaServiceAcctPEMKey)
    if err != nil {
        log.Fatal("error reading GA Service Account PEM key -", err)
    }
    // create a JWT (JSON Web Token).
    jsonWebToken := jwt.NewToken(gaServiceAcctEmail, oauthConfig.Scope, pemKey)
    // form the JWT claim set.
    jsonWebToken.ClaimSet.Aud = oauthConfig.TokenURL
    // create a basic httpclient. we will use this to send the JWT.
    httpClient := &http.Client{}
    // build the request, encode it, and then send the JWT. we get a nifty oauth.Token in return.
    oauthToken, err := jsonWebToken.Assert(httpClient)
    if err != nil {
        log.Fatal("error asserting JSON Web Token -", err)
    }
    // build the oauth transport
    oauthTransport := oauth.Transport{Config: oauthConfig}
    // set the oauthTransport's token to be the oauthToken
    oauthTransport.Token = oauthToken
    // create a new analytics service by passing in the httpclient returned from Client() that can now make oauth-authenticated requests
    analyticsService, err := analytics.New(oauthTransport.Client())
    if err != nil {
        log.Fatal("error creating Analytics Service -", err)
    }
    // create a new analytics data service by passing in the analytics service we just created
    dataGaService := analytics.NewDataGaService(analyticsService)

    // w00t! now we're talking to the core reporting API. hard stuff over, let's do a simple query.

    // if no gaEndDate specified via command line args, set it to today's date.
    if gaEndDate == "" {
        t := time.Now()
        gaEndDate = t.Format(dateLayout)
    }
    // print the query start & end dates.
    fmt.Printf("gaStartDate=%s, gaEndDate=%s\n", gaStartDate, gaEndDate)
    fmt.Printf("gaMetrics=%s\n", gaMetrics)
    // setup the query
    dataGaGetCall := dataGaService.Get(gaTableID, gaStartDate, gaEndDate, gaMetrics)
    // setup the dimensions (if any).
    if gaDimensions != "" {
        dimensions := fmt.Sprintf("ga:dimensions=%s", gaDimensions)
        fmt.Printf("gaDimensions=%s\n", dimensions)
        dataGaGetCall.Dimensions(gaDimensions)
    }
    // setup the sort order (if any).
    if gaSortOrder != "" {
        sortorder := fmt.Sprintf("ga:sort=%s", gaSortOrder)
        fmt.Printf("gaSortOrder=%s\n", sortorder)
        dataGaGetCall.Sort(gaSortOrder)
    }
    // setup the filter (if any).
    if gaFilter != "" {
        filter := fmt.Sprintf("%s", gaFilter)
        fmt.Printf("gaFilter=%s\n", filter)
        dataGaGetCall.Filters(filter)
    }
    // setup the max results we want returned.
    dataGaGetCall.MaxResults(gaMaxResults)
    // send the query to the API, get gaData back.
    gaData, err := dataGaGetCall.Do()
    if err != nil {
        log.Fatal("API error -", err)
    }
    // how much data did we get back?
    fmt.Printf("len(gaData.Rows)=%d, TotalResults=%d\n", len(gaData.Rows), gaData.TotalResults)
    // a lazy loop through the returned rows
    for row := 0; row <= len(gaData.Rows)-1; row++ {
        fmt.Printf("row=%d %v\n", row, gaData.Rows[row])
    }
}

// func: usage()

// prints out all possible flags/options when "-h" or an unknown option is used at runtime.
// exits back to shell when complete.
func usage() {
    fmt.Printf("usage: %s [OPTION] \n", os.Args[0])
    flag.PrintDefaults()
    os.Exit(2)
}