- 取得連結
- X
- 以電子郵件傳送
- 其他應用程式
程式語言:Go
功能:運用 google 各種服務
google 官方 oauth2 範例
Go實戰--golang中OAuth2.0的使用(使用google賬號進行登陸驗證)
- Package:
- Google APIs
功能:運用 google 各種服務
申請 API Key
- 進入 Google APIs
- 上方:新增專案
- 資訊頁面:點選 啟用 API 和服務
- 憑證頁面:依需求建立憑證
基本用法
- 建立 client,內建已含認證方式,自定義 client 可在 Transport 實作
- service.New(client) 建立 service 呼叫 API
- service.apiService.apiCall(...) 建立 call
- call.parameter(...) 設定各種參數
- call.Do() 送出 request
package main
import (
"fmt"
"google.golang.org/api/drive/v3"
)
func main() {
auth := NewAuth(redirectURL)
client := auth.GetClient(clientsecretPath, "drive-go.json")
service, err := drive.New(client)
if err != nil {
panic(err)
}
call := service.Files.List()
call = call.PageSize(2)
response, err := call.Do()
if err != nil {
panic(err)
}
}
oauth2 範例
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"os"
"os/user"
"path/filepath"
"github.com/pkg/errors"
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
// This variable indicates whether the script should launch a web server to
// initiate the authorization flow or just display the URL in the terminal
// window. Note the following instructions based on this setting:
// * launchWebServer = true
// 1. Use OAuth2 credentials for a web application
// 2. Define authorized redirect URIs for the credential in the Google APIs
// Console and set the RedirectURL property on the config object to one
// of those redirect URIs. For example:
// config.RedirectURL = "http://localhost:8090"
// 3. In the startWebServer function below, update the URL in this line
// to match the redirect URI you selected:
// listener, err := net.Listen("tcp", "localhost:8090")
// The redirect URI identifies the URI to which the user is sent after
// completing the authorization flow. The listener then captures the
// authorization code in the URL and passes it back to this script.
// * launchWebServer = false
// 1. Use OAuth2 credentials for an installed application. (When choosing
// the application type for the OAuth2 client ID, select "Other".)
// 2. Set the redirect URI to "urn:ietf:wg:oauth:2.0:oob", like this:
// config.RedirectURL = "urn:ietf:wg:oauth:2.0:oob"
// 3. When running the script, complete the auth flow. Then copy the
// authorization code from the browser and enter it on the command line.
const launchWebServer = true
const missingClientSecretsMessage = `
Please configure OAuth 2.0
To make this sample run, you need to populate the client_secrets.json file
found at:
%v
with information from the {{ Google Cloud Console }}{{ https://cloud.google.com/console }}For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
`
// Auth for oauth2
type Auth struct {
redirectURL *url.URL
config *oauth2.Config
useTLS bool
tlsCert, tlsKey string
}
// NewAuth create Auth
func NewAuth(redirectURL string) *Auth {
a := &Auth{}
var err error
a.redirectURL, err = url.Parse(redirectURL)
if err != nil {
log.Fatal(err)
}
return a
}
// SetTLS when redirectURL is TLS, it should be setted
func (a *Auth) SetTLS(TLSCertPath, TLSKeyPath string) {
a.tlsCert = TLSCertPath
a.tlsKey = TLSKeyPath
a.useTLS = true
}
// GetClient generate a Client. It returns the generated Client.
// clientsecret file format reference to client_secret.json.sample
func (a *Auth) GetClient(clientsecretPath, tokenFile string) *http.Client {
ctx := context.Background()
b, err := ioutil.ReadFile(clientsecretPath)
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
// If modifying the scope, delete your previously saved credentials
// at ~/.credentials/tokenFile
err = a.configFromJSON(b)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
// Use a redirect URI like this for a web app. The redirect URI must be a
// valid one for your OAuth2 credentials.
a.config.RedirectURL = a.redirectURL.String()
// Use the following redirect URI if launchWebServer=false in oauth2.go
// config.RedirectURL = "urn:ietf:wg:oauth:2.0:oob"
cacheFile, err := a.tokenCacheFile(tokenFile)
if err != nil {
log.Fatalf("Unable to get path to cached credential file. %v", err)
}
token, err := a.tokenFromFile(cacheFile)
if err != nil {
if launchWebServer {
fmt.Println("Trying to get token from web")
token, err = a.getTokenFromWeb()
} else {
fmt.Println("Trying to get token from prompt")
token, err = a.getTokenFromPrompt()
}
if err == nil {
a.saveToken(cacheFile, token)
}
}
return a.config.Client(ctx, token)
}
func (a *Auth) configFromJSON(jsonKey []byte, scope ...string) error {
type cred struct {
ClientID string `json:"client_id,omitempty"`
ClientSecret string `json:"client_secret,omitempty"`
RedirectURIs []string `json:"redirect_uris,omitempty"`
AuthURI string `json:"auth_uri,omitempty"`
TokenURI string `json:"token_uri,omitempty"`
}
var j struct {
Web *cred `json:"web,omitempty"`
Installed *cred `json:"installed,omitempty"`
}
if err := json.Unmarshal(jsonKey, &j); err != nil {
return err
}
var c *cred
switch {
case j.Web != nil:
c = j.Web
case j.Installed != nil:
c = j.Installed
default:
return fmt.Errorf("oauth2: no credentials found")
}
if len(c.RedirectURIs) < 1 {
return errors.New("oauth2: missing redirect URL in the client_credentials.json")
}
a.config = &oauth2.Config{
ClientID: c.ClientID,
ClientSecret: c.ClientSecret,
RedirectURL: c.RedirectURIs[0],
Scopes: scope,
Endpoint: oauth2.Endpoint{
AuthURL: c.AuthURI,
TokenURL: c.TokenURI,
},
}
return nil
}
// startWebServer starts a web server that listens on http://localhost:8080.
// The webserver waits for an oauth code in the three-legged auth flow.
func (a *Auth) startWebServer() (codeCh chan string, err error) {
listener, err := net.Listen("tcp", a.redirectURL.Host)
if err != nil {
return nil, errors.Wrapf(err, "net.Listen")
}
codeCh = make(chan string)
handFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
code := r.FormValue("code")
codeCh <- code // send code to OAuth flow
listener.Close()
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintf(w, "Received code: %v\r\nYou can now safely close this browser window.", code)
})
if a.useTLS {
log.Printf("create TLS Server\n")
log.Printf("certPath: %s\n", a.tlsCert)
log.Printf("keyPath: %s\n", a.tlsKey)
go http.ServeTLS(listener, handFunc, a.tlsCert, a.tlsKey)
} else {
go http.Serve(listener, handFunc)
}
return codeCh, nil
}
// Exchange the authorization code for an access token
func (a *Auth) exchangeToken(code string) (*oauth2.Token, error) {
// set access_type offline for refresh token
token, err := a.config.Exchange(oauth2.NoContext, code, oauth2.AccessTypeOffline)
if err != nil {
log.Fatalf("Unable to retrieve token %v", err)
}
return token, nil
}
// getTokenFromPrompt uses Config to request a Token and prompts the user
// to enter the token on the command line. It returns the retrieved Token.
func (a *Auth) getTokenFromPrompt() (*oauth2.Token, error) {
authURL := a.config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
var code string
fmt.Printf("Go to the following link in your browser. After completing "+
"the authorization flow, enter the authorization code on the command "+
"line: \n%v\n", authURL)
if _, err := fmt.Scan(&code); err != nil {
log.Fatalf("Unable to read authorization code %v", err)
}
fmt.Println(authURL)
return a.exchangeToken(code)
}
// getTokenFromWeb uses Config to request a Token.
// It returns the retrieved Token.
func (a *Auth) getTokenFromWeb() (*oauth2.Token, error) {
codeCh, err := a.startWebServer()
if err != nil {
fmt.Printf("Unable to start a web server. %s", err)
return nil, errors.Wrapf(err, "a.startWebServer")
}
authURL := a.config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
err = openURL(authURL)
if err != nil {
log.Fatalf("Unable to open authorization URL in web server: %v", err)
} else {
fmt.Println("Your browser has been opened to an authorization URL.",
"This program will resume once authorization has been provided.")
fmt.Println(authURL)
}
// Wait for the web server to get the code.
code := <-codeCh
return a.exchangeToken(code)
}
// tokenCacheFile generates credential file path/filename.
// It returns the generated credential path/filename.
func (a *Auth) tokenCacheFile(fileName string) (string, error) {
usr, err := user.Current()
if err != nil {
return "", err
}
tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
os.MkdirAll(tokenCacheDir, 0700)
return filepath.Join(tokenCacheDir,
url.QueryEscape(fileName)), err
}
// tokenFromFile retrieves a Token from a given file path.
// It returns the retrieved Token and any read error encountered.
func (a *Auth) tokenFromFile(file string) (*oauth2.Token, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
t := &oauth2.Token{}
err = json.NewDecoder(f).Decode(t)
defer f.Close()
return t, err
}
// saveToken uses a file path to create a file and store the
// token in it.
func (a *Auth) saveToken(file string, token *oauth2.Token) {
fmt.Println("trying to save token")
fmt.Printf("Saving credential file to: %s\n", file)
f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Fatalf("Unable to cache oauth token: %v", err)
}
defer f.Close()
json.NewEncoder(f).Encode(token)
}
參考
取得 Google API Key(金鑰) 流程,啟用服務 + 瞭解配額限制google 官方 oauth2 範例
Go實戰--golang中OAuth2.0的使用(使用google賬號進行登陸驗證)
留言
張貼留言