错误:invalid_request 缺少必需的参数:client_id in golang

huangapple go评论90阅读模式
英文:

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那里得到了以下错误:

  1. 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 (
&quot;fmt&quot;
&quot;golang.org/x/oauth2&quot;
&quot;golang.org/x/oauth2/google&quot;
&quot;io/ioutil&quot;
&quot;net/http&quot;
&quot;os&quot;
)
const htmlIndex = `&lt;html&gt;&lt;body&gt;
&lt;a href=&quot;/GoogleLogin&quot;&gt;Log in with Google&lt;/a&gt;
&lt;/body&gt;&lt;/html&gt;
`
func init() {
// Setup Google&#39;s example test keys
os.Setenv(&quot;CLIENT_ID&quot;, &quot;somrestring-otherstring.apps.googleusercontent.com&quot;)
os.Setenv(&quot;SECRET_KEY&quot;, &quot;alongcharachterjumble&quot;)
}
var (
googleOauthConfig = &amp;oauth2.Config{
RedirectURL:  &quot;http://127.0.0.1:8080/auth&quot;,  //defined in Google console
ClientID:     os.Getenv(&quot;CLIENT_ID&quot;),
ClientSecret: os.Getenv(&quot;SECRET_KEY&quot;),
Scopes: []string{&quot;https://www.googleapis.com/auth/userinfo.profile&quot;,
&quot;https://www.googleapis.com/auth/userinfo.email&quot;},
Endpoint: google.Endpoint,
}
// Some random string, random for each request
oauthStateString = &quot;random&quot;
)
func main() {
http.HandleFunc(&quot;/&quot;, handleMain)
http.HandleFunc(&quot;/GoogleLogin&quot;, handleGoogleLogin)
http.HandleFunc(&quot;/GoogleCallback&quot;, handleGoogleCallback)
fmt.Println(http.ListenAndServe(&quot;:8080&quot;, nil))
}
func handleMain(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, htmlIndex)
fmt.Println(&quot;another request made&quot;)
}
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(&quot;state&quot;)
if state != oauthStateString {
fmt.Printf(&quot;invalid oauth state, expected &#39;%s&#39;, got &#39;%s&#39;\n&quot;, oauthStateString, state)
http.Redirect(w, r, &quot;/&quot;, http.StatusTemporaryRedirect)
return
}
code := r.FormValue(&quot;code&quot;)
token, err := googleOauthConfig.Exchange(oauth2.NoContext, code)
if err != nil {
fmt.Println(&quot;Code exchange failed with &#39;%s&#39;\n&quot;, err)
http.Redirect(w, r, &quot;/&quot;, http.StatusTemporaryRedirect)
return
}
response, err := http.Get(&quot;https://www.googleapis.com/oauth2/v2/userinfo?access_token=&quot; + token.AccessToken)
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
fmt.Fprintf(w, &quot;Content: %s\n&quot;, 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(&quot;CLIENT_ID&quot;) 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 = &amp;oauth2.Config{ ... }
}

Alternatively, you can set those ENV values at the OS level before executing the actual Go program.

huangapple
  • 本文由 发表于 2017年7月6日 01:43:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/44932806.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定