github.com/chanxuehong/wechat@v0.0.0-20230222024006-36f0325263cd/mp/oauth2/session.go (about)

     1  package oauth2
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	"github.com/chanxuehong/wechat/internal/debug/api"
     8  	util2 "github.com/chanxuehong/wechat/internal/util"
     9  	"github.com/chanxuehong/wechat/oauth2"
    10  	"github.com/chanxuehong/wechat/util"
    11  	"net/http"
    12  )
    13  
    14  type Session struct {
    15  	OpenId     string `json:"openid"`            // 用户唯一标识
    16  	UnionId    string `json:"unionid,omitempty"` // 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回
    17  	SessionKey string `json:"session_key"`       // 会话密钥
    18  }
    19  
    20  type SessionInfo struct {
    21  	OpenId   string `json:"openId"`   // 用户的唯一标识
    22  	Nickname string `json:"nickName"` // 用户昵称
    23  	Gender   int    `json:"gender"`   // 用户的性别, 值为1时是男性, 值为2时是女性, 值为0时是未知
    24  	Language string `json:"language"` // 用户的语言
    25  	City     string `json:"city"`     // 普通用户个人资料填写的城市
    26  	Province string `json:"province"` // 用户个人资料填写的省份
    27  	Country  string `json:"country"`  // 国家, 如中国为CN
    28  
    29  	// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),
    30  	// 用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
    31  	AvatarUrl string `json:"avatarUrl"`
    32  	UnionId   string `json:"unionId"` // 只有在将小程序绑定到微信开放平台帐号后,才会出现该字段。
    33  }
    34  
    35  // GetSession 获取小程序会话
    36  func GetSession(Endpoint *Endpoint, code string) (session *Session, err error) {
    37  	session = &Session{}
    38  	if err = getSession(session, Endpoint.SessionCodeUrl(code), nil); err != nil {
    39  		return
    40  	}
    41  	return
    42  }
    43  
    44  // GetSessionWithClient 获取小程序会话
    45  func GetSessionWithClient(Endpoint *Endpoint, code string, httpClient *http.Client) (session *Session, err error) {
    46  	session = &Session{}
    47  	if err = getSession(session, Endpoint.SessionCodeUrl(code), httpClient); err != nil {
    48  		return
    49  	}
    50  	return
    51  }
    52  
    53  func getSession(session *Session, url string, httpClient *http.Client) (err error) {
    54  
    55  	if httpClient == nil {
    56  		httpClient = util.DefaultHttpClient
    57  	}
    58  
    59  	api.DebugPrintGetRequest(url)
    60  
    61  	httpResp, err := httpClient.Get(url)
    62  	if err != nil {
    63  		return
    64  	}
    65  	defer httpResp.Body.Close()
    66  
    67  	if httpResp.StatusCode != http.StatusOK {
    68  		return fmt.Errorf("http.Status: %s", httpResp.Status)
    69  	}
    70  
    71  	var result struct {
    72  		oauth2.Error
    73  		Session
    74  	}
    75  
    76  	if err = api.DecodeJSONHttpResponse(httpResp.Body, &result); err != nil {
    77  		return
    78  	}
    79  
    80  	if result.ErrCode != oauth2.ErrCodeOK {
    81  		return &result.Error
    82  	}
    83  
    84  	*session = result.Session
    85  
    86  	return
    87  }
    88  
    89  // GetSessionInfo 解密小程序会话加密信息
    90  func GetSessionInfo(EncryptedData, sessionKey, iv string) (info *SessionInfo, err error) {
    91  
    92  	cipherText, err := base64.StdEncoding.DecodeString(EncryptedData)
    93  
    94  	aesKey, err := base64.StdEncoding.DecodeString(sessionKey)
    95  	aesIv, err := base64.StdEncoding.DecodeString(iv)
    96  
    97  	if err != nil {
    98  		return
    99  	}
   100  
   101  	raw, err := util2.AESDecryptData(cipherText, aesKey, aesIv)
   102  
   103  	if err != nil {
   104  		return
   105  	}
   106  
   107  	if err = json.Unmarshal(raw, &info); err != nil {
   108  		return
   109  	}
   110  	return
   111  }