[Go] Google API 基本運用

程式語言:Go
Package:
Google APIs
google-api-go-client

功能:運用 google 各種服務

申請 API Key

  1. 進入 Google APIs
  2. 上方:新增專案
  3. 資訊頁面:點選 啟用 API 和服務
  4. 憑證頁面:依需求建立憑證

基本用法

  1. 建立 client,內建已含認證方式,自定義 client 可在 Transport 實作
  2. service.New(client) 建立 service 呼叫 API
  3. service.apiService.apiCall(...) 建立 call
  4. call.parameter(...) 設定各種參數
  5. call.Do() 送出 request
範例:
  1. package main
  2.  
  3. import (
  4. "fmt"
  5. "google.golang.org/api/drive/v3"
  6. )
  7.  
  8. func main() {
  9. auth := NewAuth(redirectURL)
  10. client := auth.GetClient(clientsecretPath, "drive-go.json")
  11.  
  12. service, err := drive.New(client)
  13. if err != nil {
  14. panic(err)
  15. }
  16.  
  17. call := service.Files.List()
  18. call = call.PageSize(2)
  19.  
  20. response, err := call.Do()
  21. if err != nil {
  22. panic(err)
  23. }
  24. }

oauth2 範例

  1. import (
  2. "encoding/json"
  3. "fmt"
  4. "io/ioutil"
  5. "log"
  6. "net"
  7. "net/http"
  8. "net/url"
  9. "os"
  10. "os/user"
  11. "path/filepath"
  12.  
  13. "github.com/pkg/errors"
  14. "golang.org/x/net/context"
  15. "golang.org/x/oauth2"
  16. )
  17.  
  18. // This variable indicates whether the script should launch a web server to
  19. // initiate the authorization flow or just display the URL in the terminal
  20. // window. Note the following instructions based on this setting:
  21. // * launchWebServer = true
  22. // 1. Use OAuth2 credentials for a web application
  23. // 2. Define authorized redirect URIs for the credential in the Google APIs
  24. // Console and set the RedirectURL property on the config object to one
  25. // of those redirect URIs. For example:
  26. // config.RedirectURL = "http://localhost:8090"
  27. // 3. In the startWebServer function below, update the URL in this line
  28. // to match the redirect URI you selected:
  29. // listener, err := net.Listen("tcp", "localhost:8090")
  30. // The redirect URI identifies the URI to which the user is sent after
  31. // completing the authorization flow. The listener then captures the
  32. // authorization code in the URL and passes it back to this script.
  33. // * launchWebServer = false
  34. // 1. Use OAuth2 credentials for an installed application. (When choosing
  35. // the application type for the OAuth2 client ID, select "Other".)
  36. // 2. Set the redirect URI to "urn:ietf:wg:oauth:2.0:oob", like this:
  37. // config.RedirectURL = "urn:ietf:wg:oauth:2.0:oob"
  38. // 3. When running the script, complete the auth flow. Then copy the
  39. // authorization code from the browser and enter it on the command line.
  40. const launchWebServer = true
  41.  
  42. const missingClientSecretsMessage = `
  43. Please configure OAuth 2.0
  44. To make this sample run, you need to populate the client_secrets.json file
  45. found at:
  46. %v
  47. with information from the {{ Google Cloud Console }}{{ https://cloud.google.com/console }}For more information about the client_secrets.json file format, please visit:
  48. https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
  49. `
  50.  
  51. // Auth for oauth2
  52. type Auth struct {
  53. redirectURL *url.URL
  54. config *oauth2.Config
  55.  
  56. useTLS bool
  57. tlsCert, tlsKey string
  58. }
  59.  
  60. // NewAuth create Auth
  61. func NewAuth(redirectURL string) *Auth {
  62. a := &Auth{}
  63. var err error
  64. a.redirectURL, err = url.Parse(redirectURL)
  65. if err != nil {
  66. log.Fatal(err)
  67. }
  68.  
  69. return a
  70. }
  71.  
  72. // SetTLS when redirectURL is TLS, it should be setted
  73. func (a *Auth) SetTLS(TLSCertPath, TLSKeyPath string) {
  74. a.tlsCert = TLSCertPath
  75. a.tlsKey = TLSKeyPath
  76. a.useTLS = true
  77. }
  78.  
  79. // GetClient generate a Client. It returns the generated Client.
  80. // clientsecret file format reference to client_secret.json.sample
  81. func (a *Auth) GetClient(clientsecretPath, tokenFile string) *http.Client {
  82. ctx := context.Background()
  83.  
  84. b, err := ioutil.ReadFile(clientsecretPath)
  85. if err != nil {
  86. log.Fatalf("Unable to read client secret file: %v", err)
  87. }
  88.  
  89. // If modifying the scope, delete your previously saved credentials
  90. // at ~/.credentials/tokenFile
  91. err = a.configFromJSON(b)
  92. if err != nil {
  93. log.Fatalf("Unable to parse client secret file to config: %v", err)
  94. }
  95.  
  96. // Use a redirect URI like this for a web app. The redirect URI must be a
  97. // valid one for your OAuth2 credentials.
  98. a.config.RedirectURL = a.redirectURL.String()
  99. // Use the following redirect URI if launchWebServer=false in oauth2.go
  100. // config.RedirectURL = "urn:ietf:wg:oauth:2.0:oob"
  101.  
  102. cacheFile, err := a.tokenCacheFile(tokenFile)
  103. if err != nil {
  104. log.Fatalf("Unable to get path to cached credential file. %v", err)
  105. }
  106. token, err := a.tokenFromFile(cacheFile)
  107. if err != nil {
  108. if launchWebServer {
  109. fmt.Println("Trying to get token from web")
  110. token, err = a.getTokenFromWeb()
  111. } else {
  112. fmt.Println("Trying to get token from prompt")
  113. token, err = a.getTokenFromPrompt()
  114. }
  115. if err == nil {
  116. a.saveToken(cacheFile, token)
  117. }
  118. }
  119. return a.config.Client(ctx, token)
  120. }
  121.  
  122. func (a *Auth) configFromJSON(jsonKey []byte, scope ...string) error {
  123. type cred struct {
  124. ClientID string `json:"client_id,omitempty"`
  125. ClientSecret string `json:"client_secret,omitempty"`
  126. RedirectURIs []string `json:"redirect_uris,omitempty"`
  127. AuthURI string `json:"auth_uri,omitempty"`
  128. TokenURI string `json:"token_uri,omitempty"`
  129. }
  130. var j struct {
  131. Web *cred `json:"web,omitempty"`
  132. Installed *cred `json:"installed,omitempty"`
  133. }
  134. if err := json.Unmarshal(jsonKey, &j); err != nil {
  135. return err
  136. }
  137. var c *cred
  138. switch {
  139. case j.Web != nil:
  140. c = j.Web
  141. case j.Installed != nil:
  142. c = j.Installed
  143. default:
  144. return fmt.Errorf("oauth2: no credentials found")
  145. }
  146. if len(c.RedirectURIs) < 1 {
  147. return errors.New("oauth2: missing redirect URL in the client_credentials.json")
  148. }
  149. a.config = &oauth2.Config{
  150. ClientID: c.ClientID,
  151. ClientSecret: c.ClientSecret,
  152. RedirectURL: c.RedirectURIs[0],
  153. Scopes: scope,
  154. Endpoint: oauth2.Endpoint{
  155. AuthURL: c.AuthURI,
  156. TokenURL: c.TokenURI,
  157. },
  158. }
  159.  
  160. return nil
  161. }
  162.  
  163. // startWebServer starts a web server that listens on http://localhost:8080.
  164. // The webserver waits for an oauth code in the three-legged auth flow.
  165. func (a *Auth) startWebServer() (codeCh chan string, err error) {
  166. listener, err := net.Listen("tcp", a.redirectURL.Host)
  167. if err != nil {
  168. return nil, errors.Wrapf(err, "net.Listen")
  169. }
  170. codeCh = make(chan string)
  171.  
  172. handFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  173. code := r.FormValue("code")
  174. codeCh <- code // send code to OAuth flow
  175. listener.Close()
  176. w.Header().Set("Content-Type", "text/plain")
  177. fmt.Fprintf(w, "Received code: %v\r\nYou can now safely close this browser window.", code)
  178. })
  179. if a.useTLS {
  180. log.Printf("create TLS Server\n")
  181. log.Printf("certPath: %s\n", a.tlsCert)
  182. log.Printf("keyPath: %s\n", a.tlsKey)
  183. go http.ServeTLS(listener, handFunc, a.tlsCert, a.tlsKey)
  184. } else {
  185. go http.Serve(listener, handFunc)
  186. }
  187.  
  188. return codeCh, nil
  189. }
  190.  
  191. // Exchange the authorization code for an access token
  192. func (a *Auth) exchangeToken(code string) (*oauth2.Token, error) {
  193. // set access_type offline for refresh token
  194. token, err := a.config.Exchange(oauth2.NoContext, code, oauth2.AccessTypeOffline)
  195. if err != nil {
  196. log.Fatalf("Unable to retrieve token %v", err)
  197. }
  198. return token, nil
  199. }
  200.  
  201. // getTokenFromPrompt uses Config to request a Token and prompts the user
  202. // to enter the token on the command line. It returns the retrieved Token.
  203. func (a *Auth) getTokenFromPrompt() (*oauth2.Token, error) {
  204. authURL := a.config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
  205.  
  206. var code string
  207. fmt.Printf("Go to the following link in your browser. After completing "+
  208. "the authorization flow, enter the authorization code on the command "+
  209. "line: \n%v\n", authURL)
  210.  
  211. if _, err := fmt.Scan(&code); err != nil {
  212. log.Fatalf("Unable to read authorization code %v", err)
  213. }
  214.  
  215. fmt.Println(authURL)
  216. return a.exchangeToken(code)
  217. }
  218.  
  219. // getTokenFromWeb uses Config to request a Token.
  220. // It returns the retrieved Token.
  221. func (a *Auth) getTokenFromWeb() (*oauth2.Token, error) {
  222. codeCh, err := a.startWebServer()
  223. if err != nil {
  224. fmt.Printf("Unable to start a web server. %s", err)
  225. return nil, errors.Wrapf(err, "a.startWebServer")
  226. }
  227.  
  228. authURL := a.config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
  229. err = openURL(authURL)
  230. if err != nil {
  231. log.Fatalf("Unable to open authorization URL in web server: %v", err)
  232. } else {
  233. fmt.Println("Your browser has been opened to an authorization URL.",
  234. "This program will resume once authorization has been provided.")
  235. fmt.Println(authURL)
  236. }
  237.  
  238. // Wait for the web server to get the code.
  239. code := <-codeCh
  240. return a.exchangeToken(code)
  241. }
  242.  
  243. // tokenCacheFile generates credential file path/filename.
  244. // It returns the generated credential path/filename.
  245. func (a *Auth) tokenCacheFile(fileName string) (string, error) {
  246. usr, err := user.Current()
  247. if err != nil {
  248. return "", err
  249. }
  250. tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
  251. os.MkdirAll(tokenCacheDir, 0700)
  252. return filepath.Join(tokenCacheDir,
  253. url.QueryEscape(fileName)), err
  254. }
  255.  
  256. // tokenFromFile retrieves a Token from a given file path.
  257. // It returns the retrieved Token and any read error encountered.
  258. func (a *Auth) tokenFromFile(file string) (*oauth2.Token, error) {
  259. f, err := os.Open(file)
  260. if err != nil {
  261. return nil, err
  262. }
  263. t := &oauth2.Token{}
  264. err = json.NewDecoder(f).Decode(t)
  265. defer f.Close()
  266. return t, err
  267. }
  268.  
  269. // saveToken uses a file path to create a file and store the
  270. // token in it.
  271. func (a *Auth) saveToken(file string, token *oauth2.Token) {
  272. fmt.Println("trying to save token")
  273. fmt.Printf("Saving credential file to: %s\n", file)
  274. f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
  275. if err != nil {
  276. log.Fatalf("Unable to cache oauth token: %v", err)
  277. }
  278. defer f.Close()
  279. json.NewEncoder(f).Encode(token)
  280. }

參考

取得 Google API Key(金鑰) 流程,啟用服務 + 瞭解配額限制
google 官方 oauth2 範例
Go實戰--golang中OAuth2.0的使用(使用google賬號進行登陸驗證)

留言