Go调用REST API向Azure身份验证时提示缺失grant_type参数如何解决
问题原因
- 你调用的Azure AD v1 OAuth端点
https://login.microsoftonline.com/{租户ID}/oauth2/token不支持JSON格式的请求参数,要求必须使用application/x-www-form-urlencoded格式提交表单参数,所以即使你JSON里带了grant_type字段,服务端也解析不到,才会报缺少参数的错误。 - 你的代码里还有冗余问题:已经用
ioutil.ReadAll读了响应体之后,响应流已经被读完,后续的json.NewDecoder(resp.Body).Decode会读取空内容,属于无效代码。
修正后的代码
package main import ( "bytes" "encoding/json" "io/ioutil" "log" "net/http" "net/url" ) func main() { authendpoint := "https://login.microsoftonline.com/8xxxxx7-6372-4bcb-xxx-xxxxxx/oauth2/token" // 构造表单参数,不要使用JSON格式 formData := url.Values{ "resource": {"https://graph.microsoft.com"}, "client_id": {"xxxxxxxx-7549-4ea2-b00d-xxxxxxxxxxx"}, "client_secret": {"Q.xxxxxxxxxxxxxx-6_CgA4yOi_8sS-"}, "grant_type": {"client_credentials"}, } request, err := http.NewRequest("POST", authendpoint, bytes.NewBufferString(formData.Encode())) if err != nil { log.Fatal(err) } // 修改Content-Type为表单提交格式 request.Header.Set("Content-Type", "application/x-www-form-urlencoded") client := &http.Client{} resp, err := client.Do(request) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } var res map[string]interface{} // 直接用已读取的body解析,不要重复读取resp.Body err = json.Unmarshal(body, &res) if err != nil { log.Fatal(err) } log.Printf("获取到的Access Token: %s", res["access_token"]) log.Println("完整响应内容:", string(body)) }
额外注意事项
- 如果后续要调用Azure资源管理API,把
resource参数的值改成https://management.azure.com即可 - 生产环境不要硬编码client_secret,建议通过环境变量、Azure Key Vault等方式存储敏感信息
- 要确保你注册的AAD应用已经授予了对应的Graph API/ Azure资源管理的应用权限,并且管理员已经同意了权限授予
内容的提问来源于stack exchange,提问作者Sumesh
相关产品推荐
相关产品推荐

