我们有一个oauth2端点,似乎需要一个client_credentials令牌作为承载用于令牌交换过程的初始代码。我已经成功获得了令牌。
但是,在go的oauth2客户端lib的当前实现中,Exchange()函数(参见:Exchange最终调用RetrieveToken)
它没有添加“身份验证:承载”标头,其中包含我可以在Exchange期间插入的令牌。但是,它可以添加Basic auth标头。我们的实现目前不支持基本身份验证。
如果可能的话,我想让它添加标题而不修改源代码到oauth2包。
如果我调用oauth2.RegisterBrokenAuthHeaderProvider,它可能会跳过尝试添加我的情况下需要的基本身份验证头,因为它不起作用。
然后最后调用http请求设置为POST。
代码:
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
hc, err := ContextClient(ctx)
if err != nil {
return nil, err
}
bustedAuth := !providerAuthHeaderWorks(tokenURL)
if bustedAuth {
if clientID != "" {
v.Set("client_id", clientID)
}
if clientSecret != "" {
v.Set("client_secret", clientSecret)
}
}
req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if !bustedAuth {
req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
}
r, err := ctxhttp.Do(ctx, hc, req)
if err != nil {
return nil, err
}
// rest of code ...
}
ctxhttp.Do可以采用上下文。我一直在读这些,但我不明白它们是如何工作的。我可以使用它们来添加我的标题或我可能需要的任何其他标题吗?
答案 0 :(得分:0)
我不确定这是否是最佳方式,但它似乎有效。这是由于访问auth端点而调用的重定向回调处理程序。
// Create a custom tokenSource type
type tokenSource struct{ token *oauth2.Token }
func (t *tokenSource) Token() (*oauth2.Token, error) {
fmt.Println("TokenSource!", t.token)
return t.token, nil
}
func handleCallback(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")
// Create a tokenSource and fill in our application Bearer token
ts := &tokenSource{
token: &oauth2.Token{
AccessToken: appToken.AccessToken,
TokenType: appToken.TokenType,
},
}
tr := &oauth2.Transport{
Source: ts,
}
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{
Transport: tr,
})
// myConfig defined previously and in the usual way. Look at the examples.
token, err := myConfig.Exchange(ctx, code)
if err != nil {
fmt.Printf("Code exchange failed with '%s'\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
fmt.Printf("token: %+v", token)
// token can now be used.
}