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 }