github.com/infraboard/keyauth@v0.8.1/apps/provider/auth/wxwork/auth.go (about)

     1  package wxwork
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"net/url"
     9  	"time"
    10  
    11  	"github.com/infraboard/mcube/logger/zap"
    12  )
    13  
    14  var (
    15  	URLGetToken                   = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
    16  	URLFromCodeGetUserInfo        = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo"
    17  	URLGetUserInfo         string = "https://qyapi.weixin.qq.com/cgi-bin/user/get"
    18  )
    19  
    20  type ScanCodeRequest struct {
    21  	Service string `form:"service" binding:"required"`
    22  	Code    string `form:"code" binding:"required"`
    23  	State   string `form:"state" binding:"required"`
    24  	AppID   string `form:"appid" binding:"required"`
    25  }
    26  
    27  type Response struct {
    28  	ErrCode        int    `json:"errcode"`         // 返回码
    29  	ErrMsg         string `json:"errmsg"`          // 对返回码的文本描述内容
    30  	ExpiresIN      int64  `json:"expires_in"`      // 有效期
    31  	AccessToken    string `json:"access_token"`    // 认证Token
    32  	ExternalUserID string `json:"external_userid"` // 外部联系人id,当且仅当用户是企业的客户,且跟进人在应用的可见范围内时返回。
    33  	// 如果是第三方应用调用,针对同一个客户,同一个服务商不同应用获取到的id相同
    34  	UserInfo
    35  }
    36  
    37  type WechatUser struct {
    38  	ErrCode      int    `json:"errcode"`    // 返回码
    39  	ErrMsg       string `json:"errmsg"`     // 对返回码的文本描述内容
    40  	UserID       string `json:"userid"`     // 用户ID
    41  	Avatar       string `json:"avatar"`     // 头像
    42  	Position     string `json:"position"`   // 职称
    43  	Name         string `json:"name"`       // 别名
    44  	Email        string `json:"email"`      // 邮箱
    45  	Mobile       string `json:"mobile"`     // 电话
    46  	DepartmentID []int  `json:"department"` // 部门IDs
    47  	IsLeader     int    `json:"isleader"`   //是否为负责人
    48  }
    49  
    50  type UserInfo struct {
    51  	UserID   string `json:"UserId"`   // 成员UserID
    52  	OpenID   string `json:"OpenId"`   // 非企业成员的标识,对当前企业唯一
    53  	DeviceID string `json:"DeviceId"` // 手机设备号
    54  }
    55  
    56  type Wechat struct {
    57  	AppID           string `json:"app_id" bson:"app_id"`
    58  	AgentID         string `json:"agent_id" bson:"agent_id"`
    59  	AppSecret       string `json:"app_secret" bson:"app_secret"`
    60  	AccessToken     string
    61  	ExpiresIN       int64 `json:"expires_in"`        // 有效期
    62  	CreateTokenDate int64 `json:"create_token_date"` // 创建时时间
    63  }
    64  
    65  func NewAuth(appID, appSecret, agentID string) *Wechat {
    66  	w := &Wechat{
    67  		AppID:     appID,     // 企业微信app ID
    68  		AppSecret: appSecret, // 企业微信app secret
    69  		AgentID:   agentID,   // 企业微信 应用ID
    70  	}
    71  	w.AccessToken = w.GetAccessToken()
    72  	return w
    73  }
    74  
    75  func (w *Wechat) GetAccessToken() string {
    76  	req, err := http.NewRequest(http.MethodGet, URLGetToken, nil)
    77  	if err != nil {
    78  		zap.L().Errorf("GetAccessToken http.NewRequest error", err)
    79  	}
    80  	params := url.Values{
    81  		"corpid":     []string{w.AppID},
    82  		"corpsecret": []string{w.AppSecret},
    83  	}
    84  	req.URL.RawQuery = params.Encode()
    85  	resp, err := http.DefaultClient.Do(req)
    86  	if err != nil {
    87  		zap.L().Errorf("GetAccessToken http.NewRequest Do error", err)
    88  	}
    89  	defer func() {
    90  		_ = resp.Body.Close()
    91  	}()
    92  	body, _ := ioutil.ReadAll(resp.Body)
    93  	wr := Response{}
    94  	if err := json.Unmarshal(body, &wr); err == nil {
    95  		if wr.ErrCode != 0 {
    96  			zap.L().Errorf("GetAccessToken code: %v, msg: %v\n", wr.ErrCode, wr.ErrMsg)
    97  			return ""
    98  		}
    99  		w.ExpiresIN = wr.ExpiresIN
   100  		w.CreateTokenDate = time.Now().Unix()
   101  		return wr.AccessToken
   102  	}
   103  	zap.L().Errorf("GetAccessToken empty Done")
   104  	return ""
   105  }
   106  
   107  func (w Wechat) FromCodeGetUserInfo(code, accessToken string) *Response {
   108  	if code == "" {
   109  		zap.L().Errorf("args code error! ")
   110  		return nil
   111  	}
   112  	// 通过扫码回调函数传回的code等信息获取用户信息
   113  	req, err := http.NewRequest(http.MethodGet, URLFromCodeGetUserInfo, nil)
   114  	if err != nil {
   115  		zap.L().Errorf("FromCodeGetUserInfo http.NewRequest error", err)
   116  	}
   117  	params := url.Values{
   118  		"access_token": []string{accessToken},
   119  		"code":         []string{code},
   120  	}
   121  	req.URL.RawQuery = params.Encode()
   122  
   123  	resp, err := http.DefaultClient.Do(req)
   124  	if err != nil {
   125  		zap.L().Errorf("FromCodeGetUserInfo http.NewRequest Do error", err)
   126  	}
   127  	defer func() {
   128  		_ = resp.Body.Close()
   129  	}()
   130  
   131  	body, _ := ioutil.ReadAll(resp.Body)
   132  	scr := Response{}
   133  	if err := json.Unmarshal(body, &scr); err == nil {
   134  		return &scr
   135  	}
   136  	zap.L().Errorf("FromCodeGetUserInfo json.Unmarshal error", err)
   137  	return nil
   138  }
   139  
   140  func (w *Wechat) CheckCallBack(param *ScanCodeRequest) (string, error) {
   141  	token := w.GetAccessToken()
   142  	if token == "" {
   143  		return "", errors.New("get token error!")
   144  	}
   145  
   146  	scr := w.FromCodeGetUserInfo(param.Code, token)
   147  	if scr == nil {
   148  		return "", errors.New("get user info error from token!")
   149  	}
   150  
   151  	if scr.OpenID == "OPENID" {
   152  		return "", errors.New("get openid is wrong! this not is  ID!")
   153  	}
   154  	return scr.UserID, nil
   155  }
   156  
   157  // GetUserInfo 说明文档: https://work.weixin.qq.com/api/doc/90000/90135/90196
   158  func (w *Wechat) GetUserInfo(userID string) *WechatUser {
   159  	req, err := http.NewRequest(http.MethodGet, URLGetUserInfo, nil)
   160  	if err != nil {
   161  		zap.L().Errorf("GetUserInfo http.NewRequest error", err)
   162  		return nil
   163  	}
   164  	if w.AccessToken == "" {
   165  		zap.L().Errorf("GetUserInfo token is empty!")
   166  		return nil
   167  	}
   168  	params := url.Values{
   169  		"access_token": []string{w.AccessToken},
   170  		"userid":       []string{userID},
   171  	}
   172  	req.URL.RawQuery = params.Encode()
   173  
   174  	resp, err := http.DefaultClient.Do(req)
   175  	if err != nil {
   176  		zap.L().Errorf("GetUserInfo http.NewRequest Do error", err)
   177  		return nil
   178  	}
   179  	defer func() {
   180  		_ = resp.Body.Close()
   181  	}()
   182  	body, _ := ioutil.ReadAll(resp.Body)
   183  	scr := WechatUser{}
   184  	if err := json.Unmarshal(body, &scr); err == nil {
   185  		if scr.ErrCode != 0 {
   186  			zap.L().Errorf("GetUserInfo error! code: %v, msg: %v", scr.ErrCode, scr.ErrMsg)
   187  			return nil
   188  		}
   189  		return &scr
   190  	}
   191  	zap.L().Errorf("GetUserInfo json Unmarshal error", err)
   192  	return nil
   193  }