令牌响应是400错误请求,Golang Azure Active Directory。

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

Token response was 400 bad request Golang Azure Active directory

问题

请注意,我将为您翻译以下代码片段:

Have my client id and secret correct. My redirect url is - http://localhost:8080/callback . I have allowed public client flows in my AD. But everytime i execute the code i do get the login page, i click login it does authenticate me using my email id and password. But once i enter the redirect, i get the error Handler error: token response was 400 Bad Request. Please help. 

    package main
    
    import (
    	"crypto/sha256"
    	"encoding/base64"
    	"encoding/gob"
    	"encoding/json"
    	"fmt"
    	"html/template"
    	"log"
    	"net/http"
    	"net/url"
    	"strings"
    
    	"github.com/davecgh/go-spew/spew"
    	"github.com/gorilla/sessions"
    
    	"golang.org/x/net/context"
    	"golang.org/x/oauth2"
    )
    
    const (
    	redirectURI string = "http://localhost:8080/callback"
    )
    
    // Authentication + Encryption key pairs
    var sessionStoreKeyPairs = [][]byte{
    	[]byte("something-very-secret"),
    	nil,
    }
    
    var store sessions.Store
    
    var (
    	clientID string
    	config   *oauth2.Config
    )
    
    type User struct {
    	Email       string
    	DisplayName string
    }
    
    func init() {
    	// Create file system store with no size limit
    	fsStore := sessions.NewFilesystemStore("", sessionStoreKeyPairs...)
    	fsStore.MaxLength(0)
    	store = fsStore
    
    	gob.Register(&User{})
    	gob.Register(&oauth2.Token{})
    }
    
    func main() {
    	log.SetFlags(log.LstdFlags | log.Llongfile)
    
    	clientID = "<client-id>"
    	if clientID == "" {
    		log.Fatal("AZURE_AD_CLIENT_ID must be set.")
    	}
    
    	config = &oauth2.Config{
    		ClientID:     clientID,
    		ClientSecret: "<secret-id>", 
    		RedirectURL:  redirectURI,
    
    		Endpoint: oauth2.Endpoint{
    			AuthURL:  "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize",
    			TokenURL: "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token",
    		},
    
    		Scopes: []string{"User.Read"},
    	}
    
    	http.Handle("/", handle(IndexHandler))
    	http.Handle("/callback", handle(CallbackHandler))
    
    	log.Fatal(http.ListenAndServe(":8080", nil))
    }
    
    type handle func(w http.ResponseWriter, req *http.Request) error
    
    func (h handle) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    	defer func() {
    		if r := recover(); r != nil {
    			log.Printf("Handler panic: %v", r)
    		}
    	}()
    	if err := h(w, req); err != nil {
    		log.Printf("Handler error: %v", err)
    
    		if httpErr, ok := err.(Error); ok {
    			http.Error(w, httpErr.Message, httpErr.Code)
    		}
    	}
    }
    
    type Error struct {
    	Code    int
    	Message string
    }
    
    func (e Error) Error() string {
    	if e.Message == "" {
    		e.Message = http.StatusText(e.Code)
    	}
    	return fmt.Sprintf("%d: %s", e.Code, e.Message)
    }
    
    func IndexHandler(w http.ResponseWriter, req *http.Request) error {
    	session, _ := store.Get(req, "session")
    
    	var token *oauth2.Token
    	if req.FormValue("logout") != "" {
    		session.Values["token"] = nil
    		sessions.Save(req, w)
    	} else {
    		if v, ok := session.Values["token"]; ok {
    			token = v.(*oauth2.Token)
    		}
    	}
    
    	var data = struct {
    		Token   *oauth2.Token
    		AuthURL string
    	}{
    		Token:   token,
    		AuthURL: config.AuthCodeURL(SessionState(session), oauth2.AccessTypeOnline),
    	}
    
    	return indexTempl.Execute(w, &data)
    }
    
    var indexTempl = template.Must(template.New("").Parse(`<!DOCTYPE html>
    <html>
      <head>
        <title>Azure AD OAuth2 Example</title>
    
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
      </head>
      <body class="container-fluid">
        <div class="row">
          <div class="col-xs-4 col-xs-offset-4">
            <h1>Azure AD OAuth2 Example</h1>
    {{with .Token}}
            <div id="displayName"></div>
            <a href="/?logout=true">Logout</a>
    {{else}}
            <a href="{{$.AuthURL}}">Login</a>
    {{end}}
          </div>
        </div>
    
        <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
        <script>
    {{with .Token}}
          var token = {{.}};
    
          $.ajax({
            url: 'https://graph.windows.net/me?api-version=1.6',
            dataType: 'json',
            success: function(data, status) {
            	$('#displayName').text('Welcome ' + data.displayName);
            },
            beforeSend: function(xhr, settings) {
              xhr.setRequestHeader('Authorization', 'Bearer ' + token.access_token);
            }
          });
    {{end}}
        </script>
      </body>
    </html>
    `))
    
    func CallbackHandler(w http.ResponseWriter, req *http.Request) error {
    	session, _ := store.Get(req, "session")
    
    	if req.FormValue("state") != SessionState(session) {
    		return Error{http.StatusBadRequest, "invalid callback state"}
    	}
    
    	form := url.Values{}
    	form.Set("grant_type", "authorization_code")
    	form.Set("client_id", clientID)
    	form.Set("code", req.FormValue("code"))
    	form.Set("redirect_uri", redirectURI)
    	form.Set("resource", "https://graph.windows.net/<tenant-id>/oauth2/authorize")
    
    	tokenReq, err := http.NewRequest(http.MethodPost, config.Endpoint.TokenURL, strings.NewReader(form.Encode()))
    	if err != nil {
    		return fmt.Errorf("error creating token request: %v", err)
    	}
    	tokenReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    
    	resp, err := http.DefaultClient.Do(tokenReq)
    	if err != nil {
    		return fmt.Errorf("error performing token request: %v", err)
    	}
    	defer resp.Body.Close()
    
    	if resp.StatusCode >= 400 {
    		return fmt.Errorf("token response was %s", resp.Status)
    	}
    
    	var token oauth2.Token
    	if err := json.NewDecoder(resp.Body).Decode(&token); err != nil {
    		return fmt.Errorf("error decoding JSON response: %v", err)
    	}
    
    	session.Values["token"] = &token
    	if err := sessions.Save(req, w); err != nil {
    		return fmt.Errorf("error saving session: %v", err)
    	}
    
    	http.Redirect(w, req, "/", http.StatusFound)
    	return nil
    }
    
    func SessionState(session *sessions.Session) string {
    	return base64.StdEncoding.EncodeToString(sha256.New().Sum([]byte(session.ID)))
    }
    
    func dump(v interface{}) {
    	spew.Dump(v)
    }

请注意,这是一段使用Go语言编写的代码,用于实现Azure AD OAuth2的示例。它包含了处理登录、回调和注销的功能。

如果您有任何特定的问题或需要进一步的帮助,请告诉我。

英文:

Have my client id and secret correct. My redirect url is - http://localhost:8080/callback . I have allowed public client flows in my AD. But everytime i execute the code i do get the login page, i click login it does authenticate me using my email id and password. But once i enter the redirect, i get the error Handler error: token response was 400 Bad Request. Please help.

package main
import (
&quot;crypto/sha256&quot;
&quot;encoding/base64&quot;
&quot;encoding/gob&quot;
&quot;encoding/json&quot;
&quot;fmt&quot;
&quot;html/template&quot;
&quot;log&quot;
&quot;net/http&quot;
&quot;net/url&quot;
&quot;strings&quot;
&quot;github.com/davecgh/go-spew/spew&quot;
&quot;github.com/gorilla/sessions&quot;
_ &quot;golang.org/x/net/context&quot;
&quot;golang.org/x/oauth2&quot;
)
const (
redirectURI string = &quot;http://localhost:8080/callback&quot;
)
// Authentication + Encryption key pairs
var sessionStoreKeyPairs = [][]byte{
[]byte(&quot;something-very-secret&quot;),
nil,
}
var store sessions.Store
var (
clientID string
config   *oauth2.Config
)
type User struct {
Email       string
DisplayName string
}
func init() {
// Create file system store with no size limit
fsStore := sessions.NewFilesystemStore(&quot;&quot;, sessionStoreKeyPairs...)
fsStore.MaxLength(0)
store = fsStore
gob.Register(&amp;User{})
gob.Register(&amp;oauth2.Token{})
}
func main() {
log.SetFlags(log.LstdFlags | log.Llongfile)
clientID = &quot;&lt;client-id&gt;&quot;
if clientID == &quot;&quot; {
log.Fatal(&quot;AZURE_AD_CLIENT_ID must be set.&quot;)
}
config = &amp;oauth2.Config{
ClientID:     clientID,
ClientSecret: &quot;&lt;secret-id&gt;&quot;, 
RedirectURL:  redirectURI,
Endpoint: oauth2.Endpoint{
AuthURL:  &quot;https://login.microsoftonline.com/&lt;tenant-id&gt;/oauth2/v2.0/authorize&quot;,
TokenURL: &quot;https://login.microsoftonline.com/&lt;tenant-id&gt;/oauth2/v2.0/token&quot;,
},
Scopes: []string{&quot;User.Read&quot;},
}
http.Handle(&quot;/&quot;, handle(IndexHandler))
http.Handle(&quot;/callback&quot;, handle(CallbackHandler))
log.Fatal(http.ListenAndServe(&quot;:8080&quot;, nil))
}
type handle func(w http.ResponseWriter, req *http.Request) error
func (h handle) ServeHTTP(w http.ResponseWriter, req *http.Request) {
defer func() {
if r := recover(); r != nil {
log.Printf(&quot;Handler panic: %v&quot;, r)
}
}()
if err := h(w, req); err != nil {
log.Printf(&quot;Handler error: %v&quot;, err)
if httpErr, ok := err.(Error); ok {
http.Error(w, httpErr.Message, httpErr.Code)
}
}
}
type Error struct {
Code    int
Message string
}
func (e Error) Error() string {
if e.Message == &quot;&quot; {
e.Message = http.StatusText(e.Code)
}
return fmt.Sprintf(&quot;%d: %s&quot;, e.Code, e.Message)
}
func IndexHandler(w http.ResponseWriter, req *http.Request) error {
session, _ := store.Get(req, &quot;session&quot;)
var token *oauth2.Token
if req.FormValue(&quot;logout&quot;) != &quot;&quot; {
session.Values[&quot;token&quot;] = nil
sessions.Save(req, w)
} else {
if v, ok := session.Values[&quot;token&quot;]; ok {
token = v.(*oauth2.Token)
}
}
var data = struct {
Token   *oauth2.Token
AuthURL string
}{
Token:   token,
AuthURL: config.AuthCodeURL(SessionState(session), oauth2.AccessTypeOnline),
}
return indexTempl.Execute(w, &amp;data)
}
var indexTempl = template.Must(template.New(&quot;&quot;).Parse(`&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Azure AD OAuth2 Example&lt;/title&gt;
&lt;link href=&quot;https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css&quot; rel=&quot;stylesheet&quot; integrity=&quot;sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u&quot; crossorigin=&quot;anonymous&quot;&gt;
&lt;/head&gt;
&lt;body class=&quot;container-fluid&quot;&gt;
&lt;div class=&quot;row&quot;&gt;
&lt;div class=&quot;col-xs-4 col-xs-offset-4&quot;&gt;
&lt;h1&gt;Azure AD OAuth2 Example&lt;/h1&gt;
{{with .Token}}
&lt;div id=&quot;displayName&quot;&gt;&lt;/div&gt;
&lt;a href=&quot;/?logout=true&quot;&gt;Logout&lt;/a&gt;
{{else}}
&lt;a href=&quot;{{$.AuthURL}}&quot;&gt;Login&lt;/a&gt;
{{end}}
&lt;/div&gt;
&lt;/div&gt;
&lt;script src=&quot;https://code.jquery.com/jquery-3.2.1.min.js&quot; integrity=&quot;sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;
&lt;script&gt;
{{with .Token}}
var token = {{.}};
$.ajax({
url: &#39;https://graph.windows.net/me?api-version=1.6&#39;,
dataType: &#39;json&#39;,
success: function(data, status) {
$(&#39;#displayName&#39;).text(&#39;Welcome &#39; + data.displayName);
},
beforeSend: function(xhr, settings) {
xhr.setRequestHeader(&#39;Authorization&#39;, &#39;Bearer &#39; + token.access_token);
}
});
{{end}}
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
`))
func CallbackHandler(w http.ResponseWriter, req *http.Request) error {
session, _ := store.Get(req, &quot;session&quot;)
if req.FormValue(&quot;state&quot;) != SessionState(session) {
return Error{http.StatusBadRequest, &quot;invalid callback state&quot;}
}
form := url.Values{}
form.Set(&quot;grant_type&quot;, &quot;authorization_code&quot;)
form.Set(&quot;client_id&quot;, clientID)
form.Set(&quot;code&quot;, req.FormValue(&quot;code&quot;))
form.Set(&quot;redirect_uri&quot;, redirectURI)
form.Set(&quot;resource&quot;, &quot;https://graph.windows.net/&lt;tenant-id&gt;/oauth2/authorize&quot;)
tokenReq, err := http.NewRequest(http.MethodPost, config.Endpoint.TokenURL, strings.NewReader(form.Encode()))
if err != nil {
return fmt.Errorf(&quot;error creating token request: %v&quot;, err)
}
tokenReq.Header.Set(&quot;Content-Type&quot;, &quot;application/x-www-form-urlencoded&quot;)
resp, err := http.DefaultClient.Do(tokenReq)
if err != nil {
return fmt.Errorf(&quot;error performing token request: %v&quot;, err)
}
defer resp.Body.Close()
if resp.StatusCode &gt;= 400 {
return fmt.Errorf(&quot;token response was %s&quot;, resp.Status)
}
var token oauth2.Token
if err := json.NewDecoder(resp.Body).Decode(&amp;token); err != nil {
return fmt.Errorf(&quot;error decoding JSON response: %v&quot;, err)
}
session.Values[&quot;token&quot;] = &amp;token
if err := sessions.Save(req, w); err != nil {
return fmt.Errorf(&quot;error saving session: %v&quot;, err)
}
http.Redirect(w, req, &quot;/&quot;, http.StatusFound)
return nil
}
func SessionState(session *sessions.Session) string {
return base64.StdEncoding.EncodeToString(sha256.New().Sum([]byte(session.ID)))
}
func dump(v interface{}) {
spew.Dump(v)
}

答案1

得分: 1

验证CallbackHandler,特别是TokenReq调用。

英文:

Verify CallbackHandler especially TokenReq call.

huangapple
  • 本文由 发表于 2022年6月7日 11:34:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/72525628.html
匿名

发表评论

匿名网友

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

确定