这是我到目前为止返回“400 错误”的结果。难道我做错了什么?我无法弄清楚为什么不起作用,因为请求非常简单
package main
import (
"code.google.com/p/goauth2/oauth"
"fmt"
"log"
)
func main() {
cachefile := "cache.json"
code := "4/xxxxx.8uFT5Z0slpMbJvIeHux6iLY_9k7ajw" //the code received from the URL redirect
// Set up a configuration.
config := &oauth.Config{
ClientId: "xx.apps.googleusercontent.com",
ClientSecret: "cWP3HudD3XmaP33j8",
RedirectURL: "https://crm.com/sender/gmail/auth/callBack",
Scope: "https://www.googleapis.com/auth/gmail.compose",
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://accounts.google.com/o/oauth2/token",
AccessType: "offline",
TokenCache: oauth.CacheFile(cachefile),
}
// Set up a Transport using the config.
transport := &oauth.Transport{Config: config}
token, err := config.TokenCache.Token()
if err != nil {
token, err = transport.Exchange(code)
if err != nil {
log.Fatal("Exchange:", err)
}
}
// (The Exchange method will automatically cache the token.)
transport.Token = token
fmt.Println(token)
}
结果
Exchange:OAuthError: updateToken: Unexpected HTTP status 400 Bad Request
最佳答案
我建议使用“一次性代码流”,如所述in the documentation :
To take advantage of all of the benefits of Google+ Sign-In you must use a hybrid server-side flow where a user authorizes your app on the client side using the JavaScript API client and you send a special one-time authorization code to your server. Your server exchanges this one-time-use code to acquire its own access and refresh tokens from Google for the server to be able to make its own API calls, which can be done while the user is offline. This one-time code flow has security advantages over both a pure server-side flow and over sending access tokens to your server.
由于代码只能使用一次,因此破坏用户帐户的可能性较小。
客户端代码非常简单,按照示例in step 3 .
对于服务器端,我建议使用包 oauth2而不是 goauth2
。
$ go get code.google.com/p/google-api-go-client/plus/v1
$ go get github.com/golang/oauth2
$ go get google.golang.org/appengine
出于某种原因,oauth2
包还需要 appengine
包。
可以使用函数 NewTransportWithCode 将一次性代码交换为可重复使用的 token 。 :
func exchangeCode(code string) (*oauth2.Token, *oauth2.Transport, error) {
config, err := google.NewConfig(&oauth2.Options{
ClientID: CLIENT_ID,
ClientSecret: CLIENT_SECRET,
RedirectURL: "postmessage",
Scopes: []string{"https://www.googleapis.com/auth/plus.login"},
})
if err != nil {
return &oauth2.Token{}, &oauth2.Transport{}, err
}
transport, err := config.NewTransportWithCode(code)
if err != nil {
return &oauth2.Token{}, &oauth2.Transport{}, err
}
token := transport.Token()
return token, transport, nil
}
最后,您在第 3 步中创建的代码可以将一次代码提交给监听在 /oauth2
的处理程序:
func oauth2Handler(w http.ResponseWriter, r *http.Request) {
// TODO Check request has...
// - Method: POST
// - Content-Type: application/octet-stream; charset=utf-8
// - CSRF Token http://goo.gl/mNCjJm
body, err := ioutil.ReadAll(r.Body)
defer r.Body.Close()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
code := string(body[:])
token, transport, err := exchangeCode(code)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// From here you can use the transport
client := http.Client{Transport: transport}
service, err := plus.New(&client)
if err != nil {
return nil, err
}
// https://www.googleapis.com/plus/v1/people/me
person, err := service.People.Get("me").Do()
// ...
}
func main() {
http.HandleFunc("/oauth2", oauth2Handler)
log.Fatal(http.ListenAndServe(":8000", nil))
}
缺少一些错误处理,但您明白了。
关于oauth - 如何使用 Google API 交换 OAUTH token ( Go ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25379038/