diff --git a/context/qy_access_token.go b/context/qy_access_token.go new file mode 100644 index 0000000..c76d35a --- /dev/null +++ b/context/qy_access_token.go @@ -0,0 +1,76 @@ +package context + +import ( + "encoding/json" + "fmt" + "log" + "sync" + "time" + + "github.com/silenceper/wechat/util" +) + +const ( + //qyAccessTokenURL 获取access_token的接口 + qyAccessTokenURL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s" +) + +//ResQyAccessToken struct +type ResQyAccessToken struct { + util.CommonError + + AccessToken string `json:"access_token"` + ExpiresIn int64 `json:"expires_in"` +} + +//SetQyAccessTokenLock 设置读写锁(一个appID一个读写锁) +func (ctx *Context) SetQyAccessTokenLock(l *sync.RWMutex) { + ctx.accessTokenLock = l +} + +//GetQyAccessToken 获取access_token +func (ctx *Context) GetQyAccessToken() (accessToken string, err error) { + ctx.accessTokenLock.Lock() + defer ctx.accessTokenLock.Unlock() + + accessTokenCacheKey := fmt.Sprintf("qy_access_token_%s", ctx.AppID) + val := ctx.Cache.Get(accessTokenCacheKey) + if val != nil { + accessToken = val.(string) + return + } + + //从微信服务器获取 + var resQyAccessToken ResQyAccessToken + resQyAccessToken, err = ctx.GetQyAccessTokenFromServer() + if err != nil { + return + } + + accessToken = resQyAccessToken.AccessToken + return +} + +//GetQyAccessTokenFromServer 强制从微信服务器获取token +func (ctx *Context) GetQyAccessTokenFromServer() (resQyAccessToken ResQyAccessToken, err error) { + log.Printf("GetQyAccessTokenFromServer") + url := fmt.Sprintf(qyAccessTokenURL, ctx.AppID, ctx.AppSecret) + var body []byte + body, err = util.HTTPGet(url) + if err != nil { + return + } + err = json.Unmarshal(body, &resQyAccessToken) + if err != nil { + return + } + if resQyAccessToken.ErrCode != 0 { + err = fmt.Errorf("get qy_access_token error : errcode=%v , errormsg=%v", resQyAccessToken.ErrCode, resQyAccessToken.ErrMsg) + return + } + + qyAccessTokenCacheKey := fmt.Sprintf("qy_access_token_%s", ctx.AppID) + expires := resQyAccessToken.ExpiresIn - 1500 + err = ctx.Cache.Set(qyAccessTokenCacheKey, resQyAccessToken.AccessToken, time.Duration(expires)*time.Second) + return +} diff --git a/menu/menu.go b/menu/menu.go index f4aeb6d..67fe015 100644 --- a/menu/menu.go +++ b/menu/menu.go @@ -286,7 +286,6 @@ func (menu *Menu) GetCurrentSelfMenuInfo() (resSelfMenuInfo ResSelfMenuInfo, err if err != nil { return } - fmt.Println(string(response)) err = json.Unmarshal(response, &resSelfMenuInfo) if err != nil { return diff --git a/oauth/qy_oauth.go b/oauth/qy_oauth.go new file mode 100644 index 0000000..3f6916d --- /dev/null +++ b/oauth/qy_oauth.go @@ -0,0 +1,95 @@ +package oauth + +import ( + "encoding/json" + "fmt" + "net/url" + + "github.com/silenceper/wechat/util" +) + +var ( + qyRedirectOauthURL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&agentid=%s&state=%s#wechat_redirect" + qyUserInfoURL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=%s&code=%s" + qyUserDetailURL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail" +) + +//GetQyRedirectURL 获取企业微信跳转的url地址 +func (oauth *Oauth) GetQyRedirectURL(redirectURI, agentid, scope, state string) (string, error) { + //url encode + urlStr := url.QueryEscape(redirectURI) + return fmt.Sprintf(qyRedirectOauthURL, oauth.AppID, urlStr, scope, agentid, state), nil +} + +//QyUserInfo 用户授权获取到用户信息 +type QyUserInfo struct { + util.CommonError + + UserID string `json:"UserId"` + DeviceID string `json:"DeviceId"` + UserTicket string `json:"user_ticket"` + ExpiresIn int64 `json:"expires_in"` +} + +//GetQyUserInfoByCode 根据code获取企业user_info +func (oauth *Oauth) GetQyUserInfoByCode(code string) (result QyUserInfo, err error) { + qyAccessToken, e := oauth.GetQyAccessToken() + if e != nil { + err = e + return + } + urlStr := fmt.Sprintf(qyUserInfoURL, qyAccessToken, code) + var response []byte + response, err = util.HTTPGet(urlStr) + if err != nil { + return + } + err = json.Unmarshal(response, &result) + if err != nil { + return + } + if result.ErrCode != 0 { + err = fmt.Errorf("GetQyUserInfoByCode error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg) + return + } + return +} + +//QyUserDetail 到用户详情 +type QyUserDetail struct { + util.CommonError + + UserID string `json:"UserId"` + Name string `json:"name"` + Mobile string `json:"mobile"` + Gender string `json:"gender"` + Email string `json:"email"` + Avatar string `json:"avatar"` + QrCode string `json:"qr_code"` +} + +//GetQyUserDetailUserTicket 根据user_ticket获取到用户详情 +func (oauth *Oauth) GetQyUserDetailUserTicket(userTicket string) (result QyUserDetail, err error) { + var qyAccessToken string + qyAccessToken, err = oauth.GetQyAccessToken() + if err != nil { + return + } + uri := fmt.Sprintf("%s?access_token=%s", qyUserDetailURL, qyAccessToken) + var response []byte + response, err = util.PostJSON(uri, map[string]string{ + "user_ticket": userTicket, + }) + if err != nil { + return + } + err = json.Unmarshal(response, &result) + if err != nil { + return + } + if result.ErrCode != 0 { + err = fmt.Errorf("GetQyUserDetailUserTicket Error , errcode=%d , errmsg=%s", result.ErrCode, result.ErrMsg) + return + } + return +}