小程序可在 Go 上完成微信手机号登录、测评、预约和下单,不再反代 Java。 Co-authored-by: Cursor <cursoragent@cursor.com>
85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
package wechat
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"net/http"
|
||
"net/url"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// Session is the jscode2session result.
|
||
type Session struct {
|
||
OpenID string
|
||
UnionID string
|
||
SessionKey string
|
||
}
|
||
|
||
// Client exchanges a mini-program js_code for a session.
|
||
type Client interface {
|
||
Code2Session(ctx context.Context, code string) (Session, error)
|
||
}
|
||
|
||
// APIClient calls api.weixin.qq.com.
|
||
type APIClient struct {
|
||
AppID string
|
||
Secret string
|
||
HTTP *http.Client
|
||
}
|
||
|
||
type wxSessionResp struct {
|
||
OpenID string `json:"openid"`
|
||
SessionKey string `json:"session_key"`
|
||
UnionID string `json:"unionid"`
|
||
ErrCode int `json:"errcode"`
|
||
ErrMsg string `json:"errmsg"`
|
||
}
|
||
|
||
// Enabled reports whether WeChat credentials are configured.
|
||
func (c *APIClient) Enabled() bool {
|
||
return c != nil && strings.TrimSpace(c.AppID) != "" && strings.TrimSpace(c.Secret) != ""
|
||
}
|
||
|
||
// Code2Session implements Client.
|
||
func (c *APIClient) Code2Session(ctx context.Context, code string) (Session, error) {
|
||
if !c.Enabled() {
|
||
return Session{}, errors.New("微信登录未配置")
|
||
}
|
||
code = strings.TrimSpace(code)
|
||
if code == "" {
|
||
return Session{}, errors.New("缺少微信登录码")
|
||
}
|
||
q := url.Values{}
|
||
q.Set("appid", c.AppID)
|
||
q.Set("secret", c.Secret)
|
||
q.Set("js_code", code)
|
||
q.Set("grant_type", "authorization_code")
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.weixin.qq.com/sns/jscode2session?"+q.Encode(), nil)
|
||
if err != nil {
|
||
return Session{}, err
|
||
}
|
||
cli := c.HTTP
|
||
if cli == nil {
|
||
cli = &http.Client{Timeout: 10 * time.Second}
|
||
}
|
||
resp, err := cli.Do(req)
|
||
if err != nil {
|
||
return Session{}, errors.New("微信服务暂不可用")
|
||
}
|
||
defer resp.Body.Close()
|
||
var body wxSessionResp
|
||
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
||
return Session{}, errors.New("微信服务暂不可用")
|
||
}
|
||
if body.ErrCode != 0 {
|
||
return Session{}, fmt.Errorf("微信登录失败(%d)", body.ErrCode)
|
||
}
|
||
if body.OpenID == "" || body.SessionKey == "" {
|
||
return Session{}, errors.New("微信登录失败")
|
||
}
|
||
return Session{OpenID: body.OpenID, UnionID: body.UnionID, SessionKey: body.SessionKey}, nil
|
||
}
|