github.com/chanxuehong/wechat@v0.0.0-20230222024006-36f0325263cd/mp/oauth2/README.md (about) 1 ## 微信网页授权 2 3 ```Go 4 package main 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "io" 10 "log" 11 "net/http" 12 "net/url" 13 14 "github.com/chanxuehong/rand" 15 "github.com/chanxuehong/session" 16 "github.com/chanxuehong/sid" 17 mpoauth2 "github.com/chanxuehong/wechat/mp/oauth2" 18 "github.com/chanxuehong/wechat/oauth2" 19 ) 20 21 const ( 22 wxAppId = "APPID" // 填上自己的参数 23 wxAppSecret = "APPSECRET" // 填上自己的参数 24 oauth2RedirectURI = "http://192.168.1.129:8080/page2" // 填上自己的参数 25 oauth2Scope = "snsapi_userinfo" // 填上自己的参数 26 ) 27 28 var ( 29 sessionStorage = session.New(20*60, 60*60) 30 oauth2Endpoint oauth2.Endpoint = mpoauth2.NewEndpoint(wxAppId, wxAppSecret) 31 ) 32 33 func init() { 34 http.HandleFunc("/page1", Page1Handler) 35 http.HandleFunc("/page2", Page2Handler) 36 } 37 38 // 建立必要的 session, 然后跳转到授权页面 39 func Page1Handler(w http.ResponseWriter, r *http.Request) { 40 sid := sid.New() 41 state := string(rand.NewHex()) 42 43 if err := sessionStorage.Add(sid, state); err != nil { 44 io.WriteString(w, err.Error()) 45 log.Println(err) 46 return 47 } 48 49 cookie := http.Cookie{ 50 Name: "sid", 51 Value: sid, 52 HttpOnly: true, 53 } 54 http.SetCookie(w, &cookie) 55 56 AuthCodeURL := mpoauth2.AuthCodeURL(wxAppId, oauth2RedirectURI, oauth2Scope, state) 57 log.Println("AuthCodeURL:", AuthCodeURL) 58 59 http.Redirect(w, r, AuthCodeURL, http.StatusFound) 60 } 61 62 // 授权后回调页面 63 func Page2Handler(w http.ResponseWriter, r *http.Request) { 64 log.Println(r.RequestURI) 65 66 cookie, err := r.Cookie("sid") 67 if err != nil { 68 io.WriteString(w, err.Error()) 69 log.Println(err) 70 return 71 } 72 73 session, err := sessionStorage.Get(cookie.Value) 74 if err != nil { 75 io.WriteString(w, err.Error()) 76 log.Println(err) 77 return 78 } 79 80 savedState := session.(string) // 一般是要序列化的, 这里保存在内存所以可以这么做 81 82 queryValues, err := url.ParseQuery(r.URL.RawQuery) 83 if err != nil { 84 io.WriteString(w, err.Error()) 85 log.Println(err) 86 return 87 } 88 89 code := queryValues.Get("code") 90 if code == "" { 91 log.Println("用户禁止授权") 92 return 93 } 94 95 queryState := queryValues.Get("state") 96 if queryState == "" { 97 log.Println("state 参数为空") 98 return 99 } 100 if savedState != queryState { 101 str := fmt.Sprintf("state 不匹配, session 中的为 %q, url 传递过来的是 %q", savedState, queryState) 102 io.WriteString(w, str) 103 log.Println(str) 104 return 105 } 106 107 oauth2Client := oauth2.Client{ 108 Endpoint: oauth2Endpoint, 109 } 110 token, err := oauth2Client.ExchangeToken(code) 111 if err != nil { 112 io.WriteString(w, err.Error()) 113 log.Println(err) 114 return 115 } 116 log.Printf("token: %+v\r\n", token) 117 118 userinfo, err := mpoauth2.GetUserInfo(token.AccessToken, token.OpenId, "", nil) 119 if err != nil { 120 io.WriteString(w, err.Error()) 121 log.Println(err) 122 return 123 } 124 125 json.NewEncoder(w).Encode(userinfo) 126 log.Printf("userinfo: %+v\r\n", userinfo) 127 return 128 } 129 130 func main() { 131 fmt.Println(http.ListenAndServe(":8080", nil)) 132 } 133 ``` 134 135 #### 上面的程序基本上会打印下面的内容 136 ``` 137 2016/03/11 14:44:10 AuthCodeURL: https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=http%3A%2F%2F192.168.1.129%3A8080%2Fpage2&response_type=code&scope=snsapi_userinfo&state=12fa275bac6998ba8f89a5baf13f93a0#wechat_redirect 138 2016/03/11 14:44:12 /page2?code=001e44d3e2972606638027b31e61a8dH&state=12fa275bac6998ba8f89a5baf13f93a0 139 2016/03/11 14:44:12 [WECHAT_DEBUG] [API] GET https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=001e44d3e2972606638027b31e61a8dH&grant_type=authorization_code 140 2016/03/11 14:44:13 [WECHAT_DEBUG] [API] http response body: 141 {"access_token":"OezXcEiiBSKSxW0eoylIeBXr5MlyOHqjC6Db82eo0Txphdi2X9hT8lI2PqjpL0rCFVQjLdSs4v2GQXE8BcLRz1hCQHL6wWXl9013zYMOAvE1UGCV4q-xAIlRVuDa85Mqnqw9himuhlgFUP2Kn0qcFg","expires_in":7200,"refresh_token":"OezXcEiiBSKSxW0eoylIeBXr5MlyOHqjC6Db82eo0Txphdi2X9hT8lI2PqjpL0rCZP99UMCpbrq8v2TWR7uxK5fb0ekmVFl9L1kUOsh1mjQy6rhQG5sGqFBKrkzPr9KQbjTxrvFtscFPmCOMuKi9EQ","openid":"os-IKuHd9pJ6xsn4mS7GyL4HxqI4","scope":"snsapi_userinfo"} 142 2016/03/11 14:44:13 token: &{AccessToken:OezXcEiiBSKSxW0eoylIeBXr5MlyOHqjC6Db82eo0Txphdi2X9hT8lI2PqjpL0rCFVQjLdSs4v2GQXE8BcLRz1hCQHL6wWXl9013zYMOAvE1UGCV4q-xAIlRVuDa85Mqnqw9himuhlgFUP2Kn0qcFg CreatedAt:1457678653 ExpiresIn:6000 RefreshToken:OezXcEiiBSKSxW0eoylIeBXr5MlyOHqjC6Db82eo0Txphdi2X9hT8lI2PqjpL0rCZP99UMCpbrq8v2TWR7uxK5fb0ekmVFl9L1kUOsh1mjQy6rhQG5sGqFBKrkzPr9KQbjTxrvFtscFPmCOMuKi9EQ OpenId:os-IKuHd9pJ6xsn4mS7GyL4HxqI4 UnionId: Scope:snsapi_userinfo} 143 2016/03/11 14:44:13 [WECHAT_DEBUG] [API] GET https://api.weixin.qq.com/sns/userinfo?access_token=OezXcEiiBSKSxW0eoylIeBXr5MlyOHqjC6Db82eo0Txphdi2X9hT8lI2PqjpL0rCFVQjLdSs4v2GQXE8BcLRz1hCQHL6wWXl9013zYMOAvE1UGCV4q-xAIlRVuDa85Mqnqw9himuhlgFUP2Kn0qcFg&openid=os-IKuHd9pJ6xsn4mS7GyL4HxqI4&lang=zh_CN 144 2016/03/11 14:44:13 [WECHAT_DEBUG] [API] http response body: 145 {"openid":"os-IKuHd9pJ6xsn4mS7GyL4HxqI4","nickname":"产学红","sex":1,"language":"zh_CN","city":"安庆","province":"安徽","country":"中国","headimgurl":"http:\/\/wx.qlogo.cn\/mmopen\/O1HUibMqqHXduhNiagwbE0m4zgJU2YbFkyZPG6VoH8IP2wEdFuWcnjUtrXHNl1OmCsoffYBBnkC0cy1yfsOibcenaAn2SeRNKYw\/0","privilege":[]} 146 2016/03/11 14:44:13 userinfo: &{OpenId:os-IKuHd9pJ6xsn4mS7GyL4HxqI4 Nickname:产学红 Sex:1 City:安庆 Province:安徽 Country:中国 HeadImageURL:http://wx.qlogo.cn/mmopen/O1HUibMqqHXduhNiagwbE0m4zgJU2YbFkyZPG6VoH8IP2wEdFuWcnjUtrXHNl1OmCsoffYBBnkC0cy1yfsOibcenaAn2SeRNKYw/0 Privilege:[] UnionId:} 147 ```