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  ```