accessToken.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Package context 开放平台相关context
  2. package context
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "net/url"
  7. "time"
  8. "github.com/silenceper/wechat/v2/util"
  9. )
  10. const (
  11. componentAccessTokenURL = "https://api.weixin.qq.com/cgi-bin/component/api_component_token"
  12. getPreCodeURL = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=%s"
  13. queryAuthURL = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=%s"
  14. refreshTokenURL = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=%s"
  15. getComponentInfoURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=%s"
  16. componentLoginURL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s&auth_type=%d&biz_appid=%s"
  17. bindComponentURL = "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=%d&no_scan=1&component_appid=%s&pre_auth_code=%s&redirect_uri=%s&biz_appid=%s#wechat_redirect"
  18. // TODO 获取授权方选项信息
  19. // getComponentConfigURL = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_option?component_access_token=%s"
  20. // TODO 获取已授权的账号信息
  21. // getuthorizerListURL = "POST https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_list?component_access_token=%s"
  22. )
  23. // ComponentAccessToken 第三方平台
  24. type ComponentAccessToken struct {
  25. util.CommonError
  26. AccessToken string `json:"component_access_token"`
  27. ExpiresIn int64 `json:"expires_in"`
  28. }
  29. // GetComponentAccessToken 获取 ComponentAccessToken
  30. func (ctx *Context) GetComponentAccessToken() (string, error) {
  31. accessTokenCacheKey := fmt.Sprintf("component_access_token_%s", ctx.AppID)
  32. val := ctx.Cache.Get(accessTokenCacheKey)
  33. if val == nil {
  34. return "", fmt.Errorf("cann't get component access token")
  35. }
  36. return val.(string), nil
  37. }
  38. // SetComponentAccessToken 通过component_verify_ticket 获取 ComponentAccessToken
  39. func (ctx *Context) SetComponentAccessToken(verifyTicket string) (*ComponentAccessToken, error) {
  40. body := map[string]string{
  41. "component_appid": ctx.AppID,
  42. "component_appsecret": ctx.AppSecret,
  43. "component_verify_ticket": verifyTicket,
  44. }
  45. respBody, err := util.PostJSON(componentAccessTokenURL, body)
  46. if err != nil {
  47. return nil, err
  48. }
  49. at := &ComponentAccessToken{}
  50. if err := json.Unmarshal(respBody, at); err != nil {
  51. return nil, err
  52. }
  53. if at.ErrCode != 0 {
  54. return nil, fmt.Errorf("SetComponentAccessToken Error , errcode=%d , errmsg=%s", at.ErrCode, at.ErrMsg)
  55. }
  56. accessTokenCacheKey := fmt.Sprintf("component_access_token_%s", ctx.AppID)
  57. expires := at.ExpiresIn - 1500
  58. if err := ctx.Cache.Set(accessTokenCacheKey, at.AccessToken, time.Duration(expires)*time.Second); err != nil {
  59. return nil, nil
  60. }
  61. return at, nil
  62. }
  63. // GetPreCode 获取预授权码
  64. func (ctx *Context) GetPreCode() (string, error) {
  65. cat, err := ctx.GetComponentAccessToken()
  66. if err != nil {
  67. return "", err
  68. }
  69. req := map[string]string{
  70. "component_appid": ctx.AppID,
  71. }
  72. uri := fmt.Sprintf(getPreCodeURL, cat)
  73. body, err := util.PostJSON(uri, req)
  74. if err != nil {
  75. return "", err
  76. }
  77. var ret struct {
  78. PreCode string `json:"pre_auth_code"`
  79. }
  80. if err := json.Unmarshal(body, &ret); err != nil {
  81. return "", err
  82. }
  83. return ret.PreCode, nil
  84. }
  85. // GetComponentLoginPage 获取第三方公众号授权链接(扫码授权)
  86. func (ctx *Context) GetComponentLoginPage(redirectURI string, authType int, bizAppID string) (string, error) {
  87. code, err := ctx.GetPreCode()
  88. if err != nil {
  89. return "", err
  90. }
  91. return fmt.Sprintf(componentLoginURL, ctx.AppID, code, url.QueryEscape(redirectURI), authType, bizAppID), nil
  92. }
  93. // GetBindComponentURL 获取第三方公众号授权链接(链接跳转,适用移动端)
  94. func (ctx *Context) GetBindComponentURL(redirectURI string, authType int, bizAppID string) (string, error) {
  95. code, err := ctx.GetPreCode()
  96. if err != nil {
  97. return "", err
  98. }
  99. return fmt.Sprintf(bindComponentURL, authType, ctx.AppID, code, url.QueryEscape(redirectURI), bizAppID), nil
  100. }
  101. // ID 微信返回接口中各种类型字段
  102. type ID struct {
  103. ID int `json:"id"`
  104. }
  105. // AuthBaseInfo 授权的基本信息
  106. type AuthBaseInfo struct {
  107. AuthrAccessToken
  108. FuncInfo []AuthFuncInfo `json:"func_info"`
  109. }
  110. // AuthFuncInfo 授权的接口内容
  111. type AuthFuncInfo struct {
  112. FuncscopeCategory ID `json:"funcscope_category"`
  113. }
  114. // AuthrAccessToken 授权方AccessToken
  115. type AuthrAccessToken struct {
  116. Appid string `json:"authorizer_appid"`
  117. AccessToken string `json:"authorizer_access_token"`
  118. ExpiresIn int64 `json:"expires_in"`
  119. RefreshToken string `json:"authorizer_refresh_token"`
  120. }
  121. // QueryAuthCode 使用授权码换取公众号或小程序的接口调用凭据和授权信息
  122. func (ctx *Context) QueryAuthCode(authCode string) (*AuthBaseInfo, error) {
  123. cat, err := ctx.GetComponentAccessToken()
  124. if err != nil {
  125. return nil, err
  126. }
  127. req := map[string]string{
  128. "component_appid": ctx.AppID,
  129. "authorization_code": authCode,
  130. }
  131. uri := fmt.Sprintf(queryAuthURL, cat)
  132. body, err := util.PostJSON(uri, req)
  133. if err != nil {
  134. return nil, err
  135. }
  136. var ret struct {
  137. util.CommonError
  138. Info *AuthBaseInfo `json:"authorization_info"`
  139. }
  140. if err := json.Unmarshal(body, &ret); err != nil {
  141. return nil, err
  142. }
  143. if ret.ErrCode != 0 {
  144. err = fmt.Errorf("QueryAuthCode error : errcode=%v , errmsg=%v", ret.ErrCode, ret.ErrMsg)
  145. return nil, err
  146. }
  147. return ret.Info, nil
  148. }
  149. // RefreshAuthrToken 获取(刷新)授权公众号或小程序的接口调用凭据(令牌)
  150. func (ctx *Context) RefreshAuthrToken(appid, refreshToken string) (*AuthrAccessToken, error) {
  151. cat, err := ctx.GetComponentAccessToken()
  152. if err != nil {
  153. return nil, err
  154. }
  155. req := map[string]string{
  156. "component_appid": ctx.AppID,
  157. "authorizer_appid": appid,
  158. "authorizer_refresh_token": refreshToken,
  159. }
  160. uri := fmt.Sprintf(refreshTokenURL, cat)
  161. body, err := util.PostJSON(uri, req)
  162. if err != nil {
  163. return nil, err
  164. }
  165. ret := &AuthrAccessToken{}
  166. if err := json.Unmarshal(body, ret); err != nil {
  167. return nil, err
  168. }
  169. authrTokenKey := "authorizer_access_token_" + appid
  170. if err := ctx.Cache.Set(authrTokenKey, ret.AccessToken, time.Second*time.Duration(ret.ExpiresIn-30)); err != nil {
  171. return nil, err
  172. }
  173. return ret, nil
  174. }
  175. // GetAuthrAccessToken 获取授权方AccessToken
  176. func (ctx *Context) GetAuthrAccessToken(appid string) (string, error) {
  177. authrTokenKey := "authorizer_access_token_" + appid
  178. val := ctx.Cache.Get(authrTokenKey)
  179. if val == nil {
  180. return "", fmt.Errorf("cannot get authorizer %s access token", appid)
  181. }
  182. return val.(string), nil
  183. }
  184. // AuthorizerInfo 授权方详细信息
  185. type AuthorizerInfo struct {
  186. NickName string `json:"nick_name"`
  187. HeadImg string `json:"head_img"`
  188. ServiceTypeInfo ID `json:"service_type_info"`
  189. VerifyTypeInfo ID `json:"verify_type_info"`
  190. UserName string `json:"user_name"`
  191. PrincipalName string `json:"principal_name"`
  192. BusinessInfo struct {
  193. OpenStore string `json:"open_store"`
  194. OpenScan string `json:"open_scan"`
  195. OpenPay string `json:"open_pay"`
  196. OpenCard string `json:"open_card"`
  197. OpenShake string `json:"open_shake"`
  198. }
  199. Alias string `json:"alias"`
  200. QrcodeURL string `json:"qrcode_url"`
  201. MiniProgramInfo *MiniProgramInfo `json:"MiniProgramInfo"`
  202. RegisterType int `json:"register_type"`
  203. AccountStatus int `json:"account_status"`
  204. BasicConfig *AuthorizerBasicConfig `json:"basic_config"`
  205. }
  206. // AuthorizerBasicConfig 授权账号的基础配置结构体
  207. type AuthorizerBasicConfig struct {
  208. IsPhoneConfigured bool `json:"isPhoneConfigured"`
  209. IsEmailConfigured bool `json:"isEmailConfigured"`
  210. }
  211. // MiniProgramInfo 授权账号小程序配置 授权账号为小程序时存在
  212. type MiniProgramInfo struct {
  213. Network struct {
  214. RequestDomain []string `json:"RequestDomain"`
  215. WsRequestDomain []string `json:"WsRequestDomain"`
  216. UploadDomain []string `json:"UploadDomain"`
  217. DownloadDomain []string `json:"DownloadDomain"`
  218. BizDomain []string `json:"BizDomain"`
  219. UDPDomain []string `json:"UDPDomain"`
  220. } `json:"network"`
  221. Categories []CategoriesInfo `json:"categories"`
  222. }
  223. // CategoriesInfo 授权账号小程序配置的类目信息
  224. type CategoriesInfo struct {
  225. First string `wx:"first"`
  226. Second string `wx:"second"`
  227. }
  228. // GetAuthrInfo 获取授权方的帐号基本信息
  229. func (ctx *Context) GetAuthrInfo(appid string) (*AuthorizerInfo, *AuthBaseInfo, error) {
  230. cat, err := ctx.GetComponentAccessToken()
  231. if err != nil {
  232. return nil, nil, err
  233. }
  234. req := map[string]string{
  235. "component_appid": ctx.AppID,
  236. "authorizer_appid": appid,
  237. }
  238. uri := fmt.Sprintf(getComponentInfoURL, cat)
  239. body, err := util.PostJSON(uri, req)
  240. if err != nil {
  241. return nil, nil, err
  242. }
  243. var ret struct {
  244. AuthorizerInfo *AuthorizerInfo `json:"authorizer_info"`
  245. AuthorizationInfo *AuthBaseInfo `json:"authorization_info"`
  246. }
  247. if err := json.Unmarshal(body, &ret); err != nil {
  248. return nil, nil, err
  249. }
  250. return ret.AuthorizerInfo, ret.AuthorizationInfo, nil
  251. }