英文:
Error: invalid_request Missing required parameter: client_id in golang
问题
我在使用Google OAuth2进行身份验证时遇到了困难。
我从Google开发者控制台获取了客户端ID和密钥,并编写了以下代码:
package main
import (
"fmt"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"io/ioutil"
"net/http"
"os"
)
const htmlIndex = `<html><body>
<a href="/GoogleLogin">Log in with Google</a>
</body></html>
`
func init() {
// 设置Google的示例测试密钥
os.Setenv("CLIENT_ID", "somrestring-otherstring.apps.googleusercontent.com")
os.Setenv("SECRET_KEY", "alongcharachterjumble")
}
var (
googleOauthConfig = &oauth2.Config{
RedirectURL: "http://127.0.0.1:8080/auth", // 在Google控制台中定义
ClientID: os.Getenv("CLIENT_ID"),
ClientSecret: os.Getenv("SECRET_KEY"),
Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"},
Endpoint: google.Endpoint,
}
// 一些随机字符串,每个请求都不同
oauthStateString = "random"
)
func main() {
http.HandleFunc("/", handleMain)
http.HandleFunc("/GoogleLogin", handleGoogleLogin)
http.HandleFunc("/GoogleCallback", handleGoogleCallback)
fmt.Println(http.ListenAndServe(":8080", nil))
}
func handleMain(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, htmlIndex)
fmt.Println("another request made")
}
func handleGoogleLogin(w http.ResponseWriter, r *http.Request) {
url := googleOauthConfig.AuthCodeURL(oauthStateString)
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
state := r.FormValue("state")
if state != oauthStateString {
fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
code := r.FormValue("code")
token, err := googleOauthConfig.Exchange(oauth2.NoContext, code)
if err != nil {
fmt.Println("Code exchange failed with '%s'\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
response, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken)
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
fmt.Fprintf(w, "Content: %s\n", contents)
}
但是我从Google那里得到了以下错误:
- That’s an error.
Error: invalid_request
Missing required parameter: client_id
Learn more
Request Details client_id= redirect_uri=http://127.0.0.1:8080/auth
response_type=code
scope=https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/userinfo.email state=random
这里出了什么问题?我该如何修复?
英文:
I'm having difficulty authenticating using Google OAuth2.
I've obtainedd client ID and secret from google developer console, and I came up with this code :
package main
import (
"fmt"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"io/ioutil"
"net/http"
"os"
)
const htmlIndex = `<html><body>
<a href="/GoogleLogin">Log in with Google</a>
</body></html>
`
func init() {
// Setup Google's example test keys
os.Setenv("CLIENT_ID", "somrestring-otherstring.apps.googleusercontent.com")
os.Setenv("SECRET_KEY", "alongcharachterjumble")
}
var (
googleOauthConfig = &oauth2.Config{
RedirectURL: "http://127.0.0.1:8080/auth", //defined in Google console
ClientID: os.Getenv("CLIENT_ID"),
ClientSecret: os.Getenv("SECRET_KEY"),
Scopes: []string{"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"},
Endpoint: google.Endpoint,
}
// Some random string, random for each request
oauthStateString = "random"
)
func main() {
http.HandleFunc("/", handleMain)
http.HandleFunc("/GoogleLogin", handleGoogleLogin)
http.HandleFunc("/GoogleCallback", handleGoogleCallback)
fmt.Println(http.ListenAndServe(":8080", nil))
}
func handleMain(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, htmlIndex)
fmt.Println("another request made")
}
func handleGoogleLogin(w http.ResponseWriter, r *http.Request) {
url := googleOauthConfig.AuthCodeURL(oauthStateString)
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
state := r.FormValue("state")
if state != oauthStateString {
fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
code := r.FormValue("code")
token, err := googleOauthConfig.Exchange(oauth2.NoContext, code)
if err != nil {
fmt.Println("Code exchange failed with '%s'\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
response, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken)
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
fmt.Fprintf(w, "Content: %s\n", contents)
}
But I get this error from google:
> 400. That’s an error.
>
> Error: invalid_request
>
> Missing required parameter: client_id
>
> Learn more
>
> Request Details client_id= redirect_uri=http://127.0.0.1:8080/auth
> response_type=code
> scope=https://www.googleapis.com/auth/userinfo.profile
> https://www.googleapis.com/auth/userinfo.email state=random
What's wrong here? How can I fix it?
答案1
得分: 2
错误消息表明ClientID
未初始化。
这与代码一致,因为var
声明在init
函数之前执行。
因此,当你的var
请求os.Getenv("CLIENT_ID")
时,值为空,因为init
尚未执行。
根据文档:
没有导入的包通过为其所有包级变量分配初始值,然后按照它们在源代码中出现的顺序调用所有的init函数来进行初始化,可能在多个文件中进行,如提交给编译器的方式。
https://golang.org/ref/spec#Package_initialization
要解决此问题,可以直接在var
初始化中放置字符串,或在设置值后从init
触发初始化。
例如:
var (
googleOauthConfig *oauth2.Config
)
func init() {
// 初始化环境变量
// 使用环境变量值初始化变量
googleOauthConfig = &oauth2.Config{ ... }
}
或者,可以在执行实际的Go程序之前,在操作系统级别设置这些ENV
值。
英文:
The error message indicates that ClientID
is not initialized.
That looks consistent with the code, since var
declarations are executed before the init
functions.
So when your var
requests os.Getenv("CLIENT_ID")
the value is blank since init
has not executed yet.
From the documentation:
> A package with no imports is initialized by assigning initial values to all its package-level variables followed by calling all init functions in the order they appear in the source, possibly in multiple files, as presented to the compiler
https://golang.org/ref/spec#Package_initialization
To fix this, either put the string directly in the var
initialization, or trigger the initialization from the init
after you set the values.
Like:
var (
googleOauthConfig *oauth2.Config
)
func init() {
// init ENV
// initialize the variable using ENV values
googleOauthConfig = &oauth2.Config{ ... }
}
Alternatively, you can set those ENV
values at the OS level before executing the actual Go program.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论