wx_auth.go 4.84 KB
Newer Older
haoyanbin's avatar
1  
haoyanbin committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
package wx

import (
	"errors"
	"fmt"
	"github.com/medivhzhan/weapp/v2"
)

const (
	apiLogin          = "/sns/jscode2session"
	apiGetAccessToken = "/cgi-bin/token"
	apiGetPaidUnionID = "/wxa/getpaidunionid"
)

// LoginResponse 返回给用户的数据
type LoginResponse struct {
	CommonError
	OpenID     string `json:"openid"`
	SessionKey string `json:"session_key"`
	// 用户在开放平台的唯一标识符 只在关注公众号的前提下
	UnionID string `json:"unionid"`
	Mobile  string `json:"mobile"`
}

// Login 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。
//
// appID 小程序 appID
// secret 小程序的 app secret
// code 小程序登录时获取的 code
func GetWxLoginRes(appID, secret, code, encryptedDate, iv string) (*LoginResponse, error) {
	api := baseURL + apiLogin
	loginResponse, err := getWxLoginRes(appID, secret, code, api)
	if err != nil {
		fmt.Println(111)
		return nil, err
	}
	if loginResponse.CommonError.ErrCode != 0 {
		fmt.Println(222)
		fmt.Println(loginResponse.CommonError.ErrCode)
		return nil, errors.New("code过期:" + loginResponse.CommonError.ErrMSG)
	}

	mobile, err := weapp.DecryptMobile(loginResponse.SessionKey, encryptedDate, iv)
	if err != nil {
		fmt.Println(333)
		return nil, err
	}
	loginResponse.Mobile = mobile.PhoneNumber
	return loginResponse, nil
}

func GetOpenId(appID, secret, code string) (string, error) {
	api := baseURL + apiLogin
	queries := requestQueries{
		"appid":      appID,
		"secret":     secret,
		"js_code":    code,
		"grant_type": "authorization_code",
	}
	url, err := encodeURL(api, queries)
	if err != nil {
		return "", err
	}
	res := new(LoginResponse)
	if err := getJSON(url, res); err != nil {
		return "", err
	}

	return res.OpenID, nil
}

func getWxLoginRes(appID, secret, code, api string) (*LoginResponse, error) {
	queries := requestQueries{
		"appid":      appID,
		"secret":     secret,
		"js_code":    code,
		"grant_type": "authorization_code",
	}
	url, err := encodeURL(api, queries)
	if err != nil {
		return nil, err
	}

	res := new(LoginResponse)
	if err := getJSON(url, res); err != nil {
		return nil, err
	}

	return res, nil
}

// TokenResponse 获取 access_token 成功返回数据
type TokenResponse struct {
	CommonError
	AccessToken string `json:"access_token"` // 获取到的凭证
	ExpiresIn   uint   `json:"expires_in"`   // 凭证有效时间,单位:秒。目前是7200秒之内的值。
}

// GetAccessToken 获取小程序全局唯一后台接口调用凭据(access_token)。
// 调调用绝大多数后台接口时都需使用 access_token,开发者需要进行妥善保存,注意缓存。
func GetAccessToken(appID, secret string) (*TokenResponse, error) {
	api := baseURL + apiGetAccessToken
	return getAccessToken(appID, secret, api)
}

func getAccessToken(appID, secret, api string) (*TokenResponse, error) {

	queries := requestQueries{
		"appid":      appID,
		"secret":     secret,
		"grant_type": "client_credential",
	}

	url, err := encodeURL(api, queries)
	if err != nil {
		return nil, err
	}

	res := new(TokenResponse)
	if err := getJSON(url, res); err != nil {
		return nil, err
	}

	return res, nil
}

// GetPaidUnionIDResponse response data
type GetPaidUnionIDResponse struct {
	CommonError
	UnionID string `json:"unionid"`
}

// GetPaidUnionID 用户支付完成后,通过微信支付订单号(transaction_id)获取该用户的 UnionId,
func GetPaidUnionID(accessToken, openID, transactionID string) (*GetPaidUnionIDResponse, error) {
	api := baseURL + apiGetPaidUnionID
	return getPaidUnionID(accessToken, openID, transactionID, api)
}

func getPaidUnionID(accessToken, openID, transactionID, api string) (*GetPaidUnionIDResponse, error) {
	queries := requestQueries{
		"openid":         openID,
		"access_token":   accessToken,
		"transaction_id": transactionID,
	}

	return getPaidUnionIDRequest(api, queries)
}

// GetPaidUnionIDWithMCH 用户支付完成后,通过微信支付商户订单号和微信支付商户号(out_trade_no 及 mch_id)获取该用户的 UnionId,
func GetPaidUnionIDWithMCH(accessToken, openID, outTradeNo, mchID string) (*GetPaidUnionIDResponse, error) {
	api := baseURL + apiGetPaidUnionID
	return getPaidUnionIDWithMCH(accessToken, openID, outTradeNo, mchID, api)
}

func getPaidUnionIDWithMCH(accessToken, openID, outTradeNo, mchID, api string) (*GetPaidUnionIDResponse, error) {
	queries := requestQueries{
		"openid":       openID,
		"mch_id":       mchID,
		"out_trade_no": outTradeNo,
		"access_token": accessToken,
	}

	return getPaidUnionIDRequest(api, queries)
}

func getPaidUnionIDRequest(api string, queries requestQueries) (*GetPaidUnionIDResponse, error) {
	url, err := encodeURL(api, queries)
	if err != nil {
		return nil, err
	}

	res := new(GetPaidUnionIDResponse)
	if err := getJSON(url, res); err != nil {
		return nil, err
	}

	return res, nil
}